Imports System.ComponentModel
Imports WRDB.Project

Public Class frmGraph

    ''' <summary>
    ''' Used during initialization (see Activated event)
    ''' </summary>
    Private FormIsLoaded As Boolean = False

    ''' <summary>
    ''' Set this true if want last graph to be loaded once form is loaded
    ''' </summary>
    Public LoadLast As Boolean = False

    ''' <summary>
    ''' Set this to full path of file if want it to be loaded once form is loaded
    ''' </summary>
    Public LoadFile As String = ""

    ''' <summary>
    ''' Caption to appear at top of form
    ''' </summary>
    Public FormCaption As String = "WRDB Graph 5.0"

    Private WithEvents AnimTimer As New Timer

    'most recently used file list...
    Friend mru As clsMruStripMenu

    ''' <summary>
    ''' The number of river miles to display in longitudinal profile
    ''' </summary>
    Private RMRange As Double() = {0.1, 0.5, 1, 2, 5, 10, 25, 50, 75, 100, 150, 250, 500}

    ''' <summary>
    ''' The number of days to display in time series graph
    ''' </summary>
    Private TimeRange As Double() = {4 / 24, 0.5, 1, 3, 7, 14, 30, 60, 90, 180, 365, 730, 1095, 1825, 3650, 7300, 10950, 14600, 18250, 27375, 36500}

    ''' <summary>
    ''' The number of minutes in window around specified date-time for profile graphs for displaying WRDB data
    ''' </summary>
    Private TimeWindow As Double() = {0, 1, 5, 15, 30, 60, 120, 360, 720, 1440, 4320, 10080, 20160, 43200, 129600, 259200, 525600, 52000000}

    Private LoadingSettings As Boolean = False 'set to true to prevent being prompted when programmatically adding tab pages

    Friend _OpenTables As New Generic.List(Of clsTable)

    Friend _IsModified As Boolean = False

    ''' <summary>Set this to True to cancel the current load operation</summary>
    Private _IsLoadCancelled As Boolean = False

    ''' <summary>Set this to True to cancel the current graph building operation</summary>
    Private _IsBuildCancelled As Boolean = False

    ''' <summary>
    ''' This structure will hold the initial lists displayed in the Manage Series form, to avoid having to re-query the tables each time it is opened
    ''' </summary>
    Friend Structure structSeriesLists
        Dim TableName As String
        Dim Branches() As String
        Dim Stations() As String
        Dim PCodes() As String
        Dim Dates() As String
    End Structure

    Friend SeriesLists As structSeriesLists

    ''' <summary>
    ''' Global variable used for printing
    ''' </summary>
    Friend WithEvents PrintDoc As New Printing.PrintDocument

    ''' <summary>
    ''' Global variables used for printing
    ''' </summary>
    Friend CurrentPageNum As Integer = 0, MinPageNum As Integer = 0, MaxPageNum As Integer = 0

    ''' <summary>
    ''' Global variable defining default layout name for printing to sending to image
    ''' </summary>
    Friend ActiveLayoutName As String = "Default"

    Private Sub AnimTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles AnimTimer.Tick
        With trkAnim
            If .Value = .Maximum Then
                .Value = .Minimum
            Else
                .Value = Math.Min(.Maximum, .Value + .SmallChange)
            End If
        End With
    End Sub

    Private Sub CheckDropDownItem(ByRef ts As Object, ByVal Index As Integer)
        For i As Integer = 0 To ts.DropDownItems.Count - 1
            CType(ts.DropDownItems(i), ToolStripMenuItem).Checked = i = Index
        Next
    End Sub

    ''' <summary>
    ''' Enable or disable menus and toolbar items depending on whether tables have been opened
    ''' </summary>
    Friend Sub EnableMenus()
        Try
            If ActiveGraphTab() Is Nothing Then Exit Sub
            Dim tab As Boolean = OpenTables.Count > 0
            Dim ser As Boolean = ActiveGraphTab.Series.Count > 0
            mnuFileClose.Enabled = tab
            mnuFileSaveGroup.Enabled = ser Or _IsModified
            mnuFileSaveGroupAs.Enabled = ser Or _IsModified
            mnuFileExcel.Enabled = ser
            mnuFileImage.Enabled = ser
            mnuFilePrint.Enabled = ser
            mnuViewCopy.Enabled = ser
            mnuViewZoomPrev.Enabled = ser
            mnuViewZoomLimits.Enabled = ser
            mnuViewZoomAll.Enabled = ser
            mnuViewZoomMode.Enabled = ser
            mnuViewAnimate.Enabled = ser 'And ActiveGraphTab.GraphType <> enumGraphType.TimeSeries
            mnuViewAnimateSpeed.Enabled = ser 'And ActiveGraphTab.GraphType <> enumGraphType.TimeSeries
            mnuViewGridlines.Enabled = ser
            mnuViewLegend.Enabled = ser
            mnuViewData.Enabled = ser
            mnuViewStats.Enabled = ser

            tbClose.Enabled = mnuFileClose.Enabled
            tbSave.Enabled = mnuFileSaveGroup.Enabled
            tbSaveAs.Enabled = mnuFileSaveGroupAs.Enabled
            tbOpenLast.Enabled = mnuFileOpenLast.Enabled
            tbMovie.Enabled = mnuFileMovie.Enabled
            tbArchive.Enabled = mnuFileArchive.Enabled
            tbGridlines.Enabled = mnuViewGridlines.Enabled
            tbLegend.Enabled = mnuViewLegend.Enabled
            tbAnimAvi.Enabled = mnuViewAnimate.Enabled
            tbCopy.Enabled = mnuViewCopy.Enabled
            tbImage.Enabled = mnuFileImage.Enabled
            tbPageSetup.Enabled = mnuFilePrintSetup.Enabled
            tbPrint.Enabled = mnuFilePrint.Enabled
            tbExcel.Enabled = mnuFileExcel.Enabled
            tbZoomPrev.Enabled = mnuViewZoomPrev.Enabled
            tbZoomLimits.Enabled = mnuViewZoomAll.Enabled
            tbZoomAll.Enabled = mnuViewZoomAll.Enabled
            tbTable.Enabled = mnuViewData.Enabled
            tbAnim.Visible = ActiveGraphTab.AnimationInfo.ToolbarVisible
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Set global variable GraphForm as each form is activated
    ''' </summary>
    Private Sub frmGraph_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated
        Static FirstTime As Boolean = True
        GraphForm = Me
        OpenTables = _OpenTables
        'If FormIsLoaded And FirstTime Then
        '    FirstTime = False
        '    If LoadLast Or GetSetting(REGAPP, "General", "AutoLoad", "False") Then
        '        mnuFileOpenLast.PerformClick()
        '    Else
        '        If LoadFile <> "" AndAlso My.Computer.FileSystem.FileExists(LoadFile) Then LoadSettings(LoadFile)
        '    End If
        'End If
    End Sub

    Private Sub frmGraph_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        Try
            'Opacity = 0 'to avoid flicker
            WriteProgress(Me, "Saving graph...")
            AnimTimer.Stop()
            If OpenTables.Count > 0 Then SaveSettings(My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData & "\LastGraph.Graph")

            For Each tbl As clsTable In _OpenTables
                tbl.Dispose()
            Next
            _OpenTables.Clear()

            ' Call sub to save the MRU filenames
            mru.SaveToRegistry()

            SaveWindowPos(REGAPP, Me)
            SaveSetting(REGAPP, Me.Name, "tbMainVisible", mnuToolbarMain.Checked)
            SaveSetting(REGAPP, Me.Name, "tbMainText", mnuToolbarText.Checked)
            SaveSetting(REGAPP, Me.Name, "tbStatusVisible", mnuToolbarStatus.Checked)
            SaveSetting(REGAPP, Me.Name, "tbAnimVisible", mnuToolbarAnim.Checked)
            SaveSetting(REGAPP, Me.Name, "splitMainCollapsed", splitMain.IsCollapsed)
            SaveSetting(REGAPP, Me.Name, "splitMainDistance", splitMain.ExpandedDistance)
            SaveSetting(REGAPP, Me.Name, "splitPropDistance", splitProperties.SplitterDistance)
            If OpenTables IsNot Nothing Then
                For Each tbl As clsTable In OpenTables
                    tbl.Dispose()
                Next
                OpenTables.Clear()
            End If
            OpenTables = Nothing
            If TableForm IsNot Nothing Then TableForm.Close() : TableForm = Nothing
            If StatsForm IsNot Nothing Then StatsForm.Close() : StatsForm = Nothing
            If GraphForm IsNot Nothing Then GraphForm.Dispose() : TableForm = Nothing
            GC.Collect()
            'need to run installer as late as possible to make sure WRDB is fully shut down
            'UpdatesInstalled sets ShutdownCommandline to non-empty string, and that gets executed here
            If modGraph.ShutdownCommandline <> "" Then Process.Start(ShutdownCommandline)
        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            WriteProgress(Me)
        End Try
    End Sub

    Private Sub frmGraph_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If _IsModified Then e.Cancel = Not PromptSave()
    End Sub

    Private Sub frmGraph_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Try
            'make form 'invisible' until can set visibility of options pane in Shown event
            Me.Opacity = 0

            'load tab images from resources so don't need files there
            With ilTabGraph.Images
                .Clear()
                .Add(My.Resources.graphhs)
                .Add(My.Resources.NewDocumentHS)
                .Add(My.Resources.graphgray)
            End With

            GetWindowPos(REGAPP, Me)

            splitMain.IsCollapsed = True
            'With splitMain
            '    .Panel1MinSize = 150
            '    .Panel2MinSize = 150
            '    .IsCollapsed = GetSetting(REGAPP, Name, "SplitMainCollapsed", True)
            '    .ExpandedDistance = GetSetting(REGAPP, Name, "SplitMainDistance", Width - .Panel2MinSize)
            'End With
            'splitProperties.SplitterDistance = GetSetting(REGAPP, Name, "SplitPropDistance", 200)

            'initialize mru (most recently used) menu list

            frmToolbar.GetToolbarSettings(tbMain)

            mru = New clsMruStripMenu(mnuFileRecent, AddressOf RecentFileHandler, "Software\VB and VBA Program Settings\WRDBGRAPH\Graph Files", 9)
            With mru
                .MaxShortenPathLength = 30
                .LoadFromRegistry()

                'make sure all these mru files exist
                For i As Integer = .NumEntries - 1 To 0 Step -1
                    If Not My.Computer.FileSystem.FileExists(.GetFileAt(i)) Then .RemoveFile(i)
                Next
                .SaveToRegistry()
            End With

            mnuToolbarMain.Checked = GetSetting(REGAPP, Name, "tbMainVisible", True)
            mnuToolbarText.Checked = GetSetting(REGAPP, Name, "tbMainText", True)
            mnuToolbarStatus.Checked = GetSetting(REGAPP, Name, "tbStatusVisible", True)
            mnuToolbarAnim.Checked = GetSetting(REGAPP, Name, "tbAnimVisible", False)

            mnuTbMain.Checked = mnuToolbarMain.Checked
            mnuTbText.Checked = mnuToolbarText.Checked
            mnuTbStatus.Checked = mnuToolbarStatus.Checked
            mnuTbAnim.Checked = mnuToolbarAnim.Checked

            tbAnim.Visible = mnuToolbarAnim.Checked

            'animation trackbar range is set below--will translate to date in code when it changes
            With trkAnim
                .TickStyle = TickStyle.None
                .Minimum = 0
                .Maximum = 1000000
                .TickFrequency = .Maximum / 10
                .TickStyle = TickStyle.BottomRight
            End With

            AnimTimer.Interval = 201

            If Not My.Computer.FileSystem.DirectoryExists(AppDataPath) Then My.Computer.FileSystem.CreateDirectory(AppDataPath)

            'create default layout set up to print one graph per page
            Layouts.Clear()
            Layouts.Add("Default", New clsLayout("Default"))
            With Layouts("Default")
                .Landscape = True
                .AutoAssign = True
                .NumCols = 1
                .NumRows = 1
                .DrawBorders = False
            End With

            'add a new graph tab at first position; default to

            TabGraph.TabPages.Insert(0, New TabPage)
            AddGraphTab(TabGraph.TabPages(0))
            OpenTables = _OpenTables

            CheckDropDownItem(mnuGraphType, ActiveGraphTab.GraphType)
            CheckDropDownItem(tbGraphType, ActiveGraphTab.GraphType)

            CheckDropDownItem(mnuGraphPlotVersus, ActiveGraphTab.ProfileXPlot)
            CheckDropDownItem(tbPlotVersus, ActiveGraphTab.ProfileXPlot)

            CheckDropDownItem(mnuViewAnimateSpeed, 2)
            CheckDropDownItem(tbAnimSpeed, 2)

            EnableMenus()
            EnableGraphMenus()
            Reset()

            pgGraphOptions.SelectedObject = ActiveGraphTab.GraphOptions
            tabProperties.SelectedIndex = 1

            ExpertMode = GetSetting(REGAPP, "General", "ExpertMode", "False")

            FormIsLoaded = True

            cboAxis.SelectedIndex = 0
            cboAxisIndex.SelectedIndex = 0

            If LoadLast Or GetSetting(REGAPP, "General", "AutoLoad", "False") Then
                mnuFileOpenLast.PerformClick()
            Else
                If LoadFile <> "" AndAlso My.Computer.FileSystem.FileExists(LoadFile) Then LoadSettings(LoadFile)
            End If

        Catch ex As Exception
            ErrorMsg(, ex)
            Me.Opacity = 100
        End Try
    End Sub

    ''' <summary>
    ''' Put property panel display here to hopefully work around inconsistent behavior reported by RB3
    ''' </summary>
    Private Sub frmGraph_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
        Try
            Application.DoEvents()
            With splitMain
                'sometimes the following will fail depending on how prior was shut down
                Try
                    .SuspendLayout()
                    .Panel1MinSize = 150
                    .Panel2MinSize = 150
                    .IsCollapsed = GetSetting(REGAPP, Name, "SplitMainCollapsed", True)
                    .ExpandedDistance = GetSetting(REGAPP, Name, "SplitMainDistance", Width - .Panel2MinSize)
                Catch ex As Exception
                    Debug.Print(ex.ToString)
                Finally
                    .ResumeLayout()
                End Try
                mnuViewProperties.Checked = Not .IsCollapsed
            End With
            Try
                Dim SplitDist As Integer = GetSetting(REGAPP, Name, "SplitPropDistance", 200)
                splitProperties.SplitterDistance = GetSetting(REGAPP, Name, "SplitPropDistance", 200)
            Catch ex As Exception
            End Try
            ResetTitleBar()
            mnuFileExit.Text = "E&xit " & FormCaption
            mnuHelpAbout.Text = "&About " & FormCaption
            Me.Opacity = 100

            'always check for updates
            'UpdatesInstalled(False)

        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFileClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuFileClose.Click
        Try
            With New frmClose
                For Each tbl As clsTable In OpenTables
                    .lstTables.Items.Add(tbl.ToString)
                Next
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    For i As Integer = 0 To .lstTables.SelectedItems.Count - 1
                        For Each tbl As clsTable In OpenTables
                            If tbl.ToString = .lstTables.SelectedItems.Item(i) Then
                                'remove all series that reference table
                                For j As Integer = 0 To TabGraph.TabCount - 2
                                    With ActiveGraphTab(j)
                                        For k As Integer = .Series.Count - 1 To 0 Step -1
                                            If .Series(k).Table IsNot Nothing AndAlso .Series(k).Table.Equals(tbl) Then
                                                .Series(k).RemoveZedCurve()
                                                .Series.RemoveAt(k)
                                            End If
                                        Next
                                        .ResetYAxes()
                                        .Zed.AxisChange()
                                        .Zed.Refresh()
                                    End With
                                Next
                                tbl.Dispose()
                                OpenTables.Remove(tbl)
                                Exit For
                            End If
                        Next
                    Next
                    EnableMenus()
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Select a single open table and change it to a different one, redefining existing series along the way
    ''' </summary>
    Private Sub mnuFileReplace_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuFileReplace.Click
        Try
            If Not ExpertMode AndAlso WarningMsg("This routine will replace an loaded data table or file with a new one that you select. Each series on all tabs will be examined and have its assigned data table/file replaced if appropriate, the selected StationID and PCode will be retained if possible, however if they are not found in the new data table/file, they will be reset without warning. Therefore, you should select a 'compatible' data file to retain series assignments.\n\nDo you want to continue?") = Windows.Forms.DialogResult.Cancel Then Exit Sub

            Dim OldTableName As String
            Dim OldTable As clsTable = Nothing
            Dim NewTable As clsTable = Nothing

            Select Case OpenTables.Count
                Case 0
                    WarningMsg("No tables have been loaded for this graph, so you cannot replace anything.")
                    Exit Sub
                Case 1
                    If Not ExpertMode Then WarningMsg("The only loaded table ({0}) has been automatically selected for replacement.", OpenTables(0).ToString)
                    OldTableName = OpenTables(0).ToString
                Case Else
                    With New frmClose
                        .Text = "Replace Table or File"
                        .btnSelectAll.Enabled = False
                        .lstTables.SelectionMode = SelectionMode.One

                        For Each tbl As clsTable In OpenTables
                            .lstTables.Items.Add(tbl.ToString)
                        Next

                        If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then OldTableName = .lstTables.Text Else Exit Sub
                    End With
            End Select

            For Each tbl As clsTable In OpenTables
                If tbl.ToString = OldTableName Then
                    OldTable = tbl
                    Exit For
                End If
            Next

            'single table is selected, now prompt for new table to replace it with
            'use generic browser rather than file browser so can get WRDB table or file

            With New frmSelectTable("", ExpertMode)
                .Text = "Replace " & OldTableName & " With Table or File"
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then NewTable = .SelectedTables(0) Else Exit Sub
            End With

            If String.Equals(OldTable.ToString, NewTable.ToString) Then
                WarningMsg("You cannot replace a table with itself.")
                Exit Sub
            End If

            'now update all referenced series with the new data
            If Not OpenTables.Contains(NewTable) Then OpenTables.Add(NewTable)

            'change all series that reference table
            For j As Integer = 0 To TabGraph.TabCount - 2
                With ActiveGraphTab(j)
                    For k As Integer = .Series.Count - 1 To 0 Step -1
                        If .Series(k).Table IsNot Nothing AndAlso .Series(k).Table.Equals(OldTable) Then
                            .Series(k).ReplaceTable(NewTable)
                        End If
                    Next
                    .ResetYAxes()
                    .Zed.AxisChange()
                    .Zed.Refresh()
                    If .Series.Count = 1 Then ActiveGraphTab.ZoomExtents()
                End With
            Next

            OpenTables.Remove(OldTable)
            OldTable.Dispose()

            EnableMenus()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFileExcel_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileExcel.Click
        Try
            Dim imin, imax As Integer
            If ApplyToAllTabs Then
                imin = 0 : imax = TabGraph.TabCount - 2
            Else
                imin = TabGraph.SelectedIndex : imax = imin
            End If
            For i As Integer = imin To imax
                ActiveGraphTab(i).SendToExcel()
            Next
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFileExit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileExit.Click
        Close()
    End Sub

    Private Sub mnuFileNew_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileNew.Click
        Try
            If _IsModified AndAlso Not PromptSave() Then Exit Sub
            With TabGraph
                For i As Integer = .TabCount - 2 To 0 Step -1
                    .TabPages.RemoveAt(i)
                Next
                .TabPages.Insert(0, "")
                AddGraphTab(.TabPages(0))
                .SelectedIndex = 0
            End With
            For Each tbl As clsTable In OpenTables
                tbl.Dispose()
            Next

            OpenTables.Clear()

            'allow user to select template file
            With New OpenFileDialog
                .CheckFileExists = True
                .DefaultExt = ".graph"
                .Filter = "Graph Settings Files (*.graph)|*.graph"
                .InitialDirectory = GetSetting(REGAPP, "General", "LastOpenDir", My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData)
                .Multiselect = False
                .ReadOnlyChecked = True
                .Title = "Select Template File or Cancel for Default"
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    LoadSettings(.FileName, False, True)
                    _IsModified = True
                    SaveSetting(REGAPP, "General", "LastOpenDir", IO.Path.GetDirectoryName(.FileName))
                End If
            End With
            GroupFileName = ""
            ResetTitleBar()
            EnableMenus()
            EnableGraphMenus()
            If TableForm IsNot Nothing Then TableForm.Refresh()
            If StatsForm IsNot Nothing Then StatsForm.Refresh()
            TabGraph.Select()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFileOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuFileOpen.Click, mnuFileOpenTable.Click
        Try
            SaveSetting(REGAPP, "General", "LastOpenType", IIf(sender Is mnuFileOpen, "File", "Table"))
            ManageSeries(True)
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFileOpenGroup_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileOpenGroup.Click
        Try
            Dim FileName As String = ""
            Dim ext As String = ""
            Dim ConfirmTables As Boolean = GetSetting(REGAPP, "General", "ConfirmTables", "False")
            With New OpenFileDialog
                .AddExtension = True
                .CheckFileExists = True
                .CheckPathExists = True
                .DefaultExt = ".graph"
                .Filter = "All Supported Formats|*.graph;*.bmd;*.db;*.xls*;*.txt;*.csv;*.dbf;*.dss;*.wdm;*.out;*.air;*.mdb;*.sdb;*.fdb;*.sdf|" & _
                          "Graph Settings Files|*.graph|" &
                          "Graph Settings Files--Confirm Tables|*.graph|" &
                          "Binary Modeling Data Files|*.bmd|" &
                          "Paradox (WRDB) Tables|*.db|" &
                          "Excel Spreadsheet Files|*.xls*|" &
                          "Tab-delimited Text Files|*.txt|" &
                          "Comma-separated Text Files|*.csv|" &
                          "dBase Tables|*.dbf|" &
                          "COE Data Storage System Files (*.dss)|*.dss|" &
                          "Watershed Data Management Files (*.wdm)|*.wdm|" &
                          "LSPC/EFDC Output Files (*.out)|*.out|" &
                          "LSPC Input Files (*.air)|*.air|" &
                          "Access Database Files|*.mdb|" &
                          "Sqlite Database Files|*.sdb|" &
                          "Firebird Database Files|*.fdb|" &
                          "SQL Server CE Files|*.sdf"
                .FilterIndex = GetSetting(REGAPP, "General", "FileFilter", 0)
                .InitialDirectory = GetSetting(REGAPP, "General", "LastOpenDir", AppDataPath)
                .Title = "Open Graph or Data File"
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    SaveSetting(REGAPP, Me.Name, "FileFilter", .FilterIndex)
                    If Not My.Computer.FileSystem.FileExists(.FileName) Then .Dispose() : Exit Sub
                    FileName = .FileName
                    Dim FilterIndex As Integer = .FilterIndex
                    If FilterIndex = 3 Then ConfirmTables = True
                    ext = IO.Path.GetExtension(FileName).ToUpper
                    Dim key As String = ""
                    SaveSetting(REGAPP, "General", "LastOpenDir", IO.Path.GetDirectoryName(FileName))
                    SaveSetting(REGAPP, "General", "FileFilter", .FilterIndex)
                Else
                    .Dispose()
                    Exit Sub
                End If
            End With

            If ext = ".GRAPH" Then
                If _IsModified AndAlso Not PromptSave() Then Exit Sub

                TabGraph.Enabled = False
                splitMain.Enabled = False
                tbMain.Enabled = False
                mnuMain.Enabled = False
                GroupFileName = FileName
                Try
                    ResetTitleBar()
                    LoadSettings(FileName, , ConfirmTables)
                Catch ex As Exception
                Finally
                    TabGraph.Enabled = True
                    splitMain.Enabled = True
                    tbMain.Enabled = True
                    mnuMain.Enabled = True
                End Try

                SaveSetting(REGAPP, Me.Name, "GroupDir", IO.Path.GetDirectoryName(GroupFileName))
                mru.AddFile(GroupFileName)            ' Call sub to add this file as an MRU
                SaveSetting(REGAPP, "General", "LastOpenDir", IO.Path.GetDirectoryName(FileName))
            Else
                SaveSetting(REGAPP, "General", "LastOpenDir", IO.Path.GetDirectoryName(FileName))
                Dim lstTbl As New Generic.List(Of clsTable)
                lstTbl.Add(New clsTable(GroupFileName, ExpertMode))
                Select Case ext
                    Case ".BMD"
                        If Not lstTbl(0).CreateBMDTable(FileName) Then Exit Sub
                        lstTbl(0).TableName = FileName
                    Case ".TXT", ".CSV", ".DBF", ".DB"
                        If Not lstTbl(0).CreateDatabaseTable(IO.Path.GetDirectoryName(FileName), IO.Path.GetFileName(FileName)) Then Exit Sub
                    Case ".OUT", ".AIR"
                        If Not lstTbl(0).CreateWRDBDataTable(FileName) Then Exit Sub
                    Case Else
                        'If Not tbl.CreateOtherProject(IO.Path.GetDirectoryName(FileName), IO.Path.GetFileName(FileName)) Then Exit Sub
                        With New frmSelectTable(FileName, ExpertMode)
                            .InitialDatabaseFile = FileName
                            If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                                For Each tbl As clsTable In .SelectedTables
                                    lstTbl.Add(tbl)
                                Next
                            Else
                                lstTbl.Clear()
                            End If
                            .Dispose()
                            If lstTbl.Count = 0 Then Exit Sub
                        End With
                End Select
                For Each tbl As clsTable In lstTbl
                    Dim found As Boolean = False
                    For Each t As clsTable In OpenTables
                        If t.Equals(tbl) Then
                            Application.UseWaitCursor = False
                            If Not ExpertMode Then WarningMsg("You cannot add a given data file more than once.")
                            found = True
                            Exit For
                        End If
                    Next
                    If Not found Then
                        OpenTables.Add(tbl)
                        mnuToolsManage.PerformClick()
                    End If
                Next
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Set title bar to include name of just opened or saved group file
    ''' </summary>
    Private Sub ResetTitleBar()
        If GroupFileName = "" Then
            Text = FormCaption
        Else
            Text = IO.Path.GetFileName(GroupFileName) & " - " & FormCaption
        End If
    End Sub

    Private Sub mnuFileOpenLast_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileOpenLast.Click
        Try
            If mnuFileRecent.DropDownItems.Count > 0 Then mnuFileRecent.DropDownItems(0).PerformClick()
            'GroupFileName = ""
            'Dim FileName As String = My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData & "\LastGraph.Graph"
            'TabGraph.Enabled = False
            'splitMain.Enabled = False
            'tbMain.Enabled = False
            'mnuMain.Enabled = False
            'Try
            '    ResetTitleBar()
            '    If My.Computer.FileSystem.FileExists(FileName) Then LoadSettings(FileName)
            'Catch ex As Exception
            'Finally
            '    TabGraph.Enabled = True
            '    splitMain.Enabled = True
            '    tbMain.Enabled = True
            '    mnuMain.Enabled = True
            'End Try
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub PrintDoc_PrintPage(sender As Object, e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDoc.PrintPage
        Try
            Dim ps As Printing.PageSettings = PrintDoc.DefaultPageSettings

            Dim PrintWidth As Double = (IIf(ps.Landscape, ps.PaperSize.Height, ps.PaperSize.Width) - ps.Margins.Left - ps.Margins.Right) / 100
            Dim PrintHeight As Double = (IIf(ps.Landscape, ps.PaperSize.Width, ps.PaperSize.Height) - ps.Margins.Top - ps.Margins.Bottom) / 100

            Dim Layout As clsLayout = Nothing
            If Not Layouts.TryGetValue(ActiveLayoutName, Layout) Then Exit Sub

            Dim Margin As Double = Layout.RowColMargin  'distance between rows & columns

            For r As Integer = 0 To Layout.NumRows - 1
                For c As Integer = 0 To Layout.NumCols - 1
                    Dim BaseDimension As Double = PrintWidth
                    Dim Width As Double = (PrintWidth - Margin * (Layout.NumCols - 1)) / Layout.NumCols
                    Dim Height As Double = (PrintHeight - Margin * (Layout.NumRows - 1)) / Layout.NumRows
                    Dim XOffset As Double = c * Width + Margin * c
                    Dim YOffset As Double = r * Height + Margin * r
                    If Layout.AutoAssign Then
                        PrintGraphPane(ActiveGraphTab(CurrentPageNum - 1), BaseDimension, Width, Height, XOffset, YOffset, e.Graphics)
                        CurrentPageNum += 1
                        If CurrentPageNum > MaxPageNum Then
                            e.HasMorePages = False
                            Exit Sub
                        End If
                    ElseIf CurrentPageNum <= Layout.PageContents.Count Then
                        Dim CalibrationName As String = "", Branch As String = "", Station As String = "", Parameter As String = ""
                        If Layout.PageContents(CurrentPageNum - 1).Item(c, r) = "None" Then
                            'don't do anything
                        ElseIf clsCalibration.TryParseCalibrationString(Layout.PageContents(CurrentPageNum - 1).Item(c, r), CalibrationName, Branch, Station, Parameter) Then 'is calibration statistics report
                            Dim Html As String = CalibrationTable(CalibrationName).Calibration.CreateReport(Station, Parameter, HTMLBuilder.clsHTMLBuilder.enumFontSize.Huge)
                            PrintGraphPane(Html, BaseDimension, Width, Height, XOffset, YOffset, e.Graphics)
                        Else
                            For i As Integer = 0 To TabGraph.TabCount - 1
                                If TabGraph.TabPages(i).Text = Layout.PageContents(CurrentPageNum - 1).Item(c, r) Then
                                    PrintGraphPane(ActiveGraphTab(i), BaseDimension, Width, Height, XOffset, YOffset, e.Graphics)
                                    Exit For
                                End If
                            Next
                        End If
                    End If
                Next
            Next
            CurrentPageNum += 1
            If Layout.AutoAssign Then
                e.HasMorePages = CurrentPageNum <= MaxPageNum
            Else
                e.HasMorePages = CurrentPageNum <= Layout.PageContents.Count And CurrentPageNum <= MaxPageNum
            End If

        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Put image of specified graph tab into correct position on printer page
    ''' </summary>
    ''' <param name="GraphTab">Graph to render</param>
    ''' <param name="BaseDimension">Width (inches) to use to set font size (usually full width of page)</param>
    ''' <param name="PrintWidth">Width (inches) of cell where graph is to be placed</param>
    ''' <param name="PrintHeight">Height (inches) of cell where graph is to be placed</param>
    ''' <param name="XOffset">Horizontal offset (inches) of upper left of graph</param>
    ''' <param name="YOffset">Vertical offset (inches) of upper left of graph</param>
    ''' <param name="g">Object to render to </param>
    Private Sub PrintGraphPane(GraphTab As clsGraphTab, BaseDimension As Double, PrintWidth As Double, PrintHeight As Double, XOffset As Double, YOffset As Double, g As Graphics)

        Dim dpiX As Integer = Me.CreateGraphics.DpiX
        Dim dpiXPrinter As Integer = g.DpiX
        Dim ps As Printing.PageSettings = PrintDoc.DefaultPageSettings

        With GraphTab
            .Zed.Visible = False

            'resize graph to provide desired resolution

            .Zed.GraphPane.IsFontsScaled = True
            .Zed.GraphPane.IsPenWidthScaled = True
            .Zed.GraphPane.Border.IsVisible = Layouts(ActiveLayoutName).DrawBorders
            .Zed.Dock = DockStyle.None

            Dim SavedFontScaleFactor As Double = .GraphOptions.FontScaleFactor
            .GraphOptions.FontScaleFactor = 1.0

            .Zed.GraphPane.BaseDimension = BaseDimension
            .Zed.Width = PrintWidth * dpiXPrinter
            .Zed.Height = PrintHeight * dpiXPrinter
            .Zed.Refresh()

            Dim img As Image = .Zed.GraphPane.GetImage(.Zed.Width, .Zed.Height, dpiXPrinter)
            g.DrawImage(img, New Point(ps.Margins.Left - ps.PrintableArea.X + XOffset * 100, ps.Margins.Top - ps.PrintableArea.Y + YOffset * 100))

            .GraphOptions.FontScaleFactor = SavedFontScaleFactor
            .Zed.Dock = DockStyle.Fill
            .Zed.GraphPane.IsFontsScaled = False
            .Zed.GraphPane.IsPenWidthScaled = False
            .Zed.Visible = True

        End With
    End Sub

    ''' <summary>
    ''' Put image of HTML report into correct position on printer page
    ''' </summary>
    ''' <param name="Html">HTML contents to render</param>
    ''' <param name="BaseDimension">Width (inches) to use to set font size (usually full width of page)</param>
    ''' <param name="PrintWidth">Width (inches) of cell where graph is to be placed</param>
    ''' <param name="PrintHeight">Height (inches) of cell where graph is to be placed</param>
    ''' <param name="XOffset">Horizontal offset (inches) of upper left of graph</param>
    ''' <param name="YOffset">Vertical offset (inches) of upper left of graph</param>
    ''' <param name="g">Object to render to </param>
    Private Sub PrintGraphPane(Html As String, BaseDimension As Double, PrintWidth As Double, PrintHeight As Double, XOffset As Double, YOffset As Double, g As Graphics)

        Dim dpiX As Integer = Me.CreateGraphics.DpiX
        Dim dpiXPrinter As Integer = g.DpiX
        Dim ps As Printing.PageSettings = PrintDoc.DefaultPageSettings
        Dim wb As New WebBrowser
        With wb
            'don't want to render to screen resolution: when it prints it looks fuzzy
            'must increase font size when increase client size; do this by trial and error
            Dim SizeMult As Double = 3

            .ClientSize = New Size(PrintWidth * dpiX * SizeMult, PrintHeight * dpiX * SizeMult)
            .ScrollBarsEnabled = False
            .DocumentText = Html
            While .ReadyState <> WebBrowserReadyState.Complete
                Application.DoEvents()
            End While
            Dim bmp As New Bitmap(.ClientSize.Width, .ClientSize.Height)
            bmp.SetResolution(dpiX * SizeMult, dpiX * SizeMult)

            .DrawToBitmap(bmp, New Rectangle(0, 0, .ClientSize.Width, .ClientSize.Height))

            g.DrawImage(bmp, New Point(ps.Margins.Left - ps.PrintableArea.X + XOffset * 100, ps.Margins.Top - ps.PrintableArea.Y + YOffset * 100))

            .Dispose()
            bmp.Dispose()

        End With
    End Sub

    Private Sub mnuFilePrint_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFilePrint.Click
        Try

            If Not CBool(GetSetting(REGAPP, frmInfoMsg.SECTIONNAME, "Page Setup", "False")) Then 'have not told it to hide
                With New frmLayout
                    .DefaultLayoutName = ActiveLayoutName
                    .chkHide.Visible = True
                    .btnClose.Text = "Print"
                    .ShowDialog(Me)
                    .Dispose()
                End With
            End If

            With New PrintDialog
                .AllowCurrentPage = Layouts(ActiveLayoutName).AutoAssign Or Layouts(ActiveLayoutName).PageContents.Count > 1
                .AllowSomePages = Layouts(ActiveLayoutName).AutoAssign Or Layouts(ActiveLayoutName).PageContents.Count > 1
                .AllowSelection = False
                .UseEXDialog = True

                .Document = PrintDoc

                Dim Layout As clsLayout = Layouts(ActiveLayoutName)

                With .Document.PrinterSettings
                    .FromPage = 1
                    If Layout.AutoAssign Then
                        .ToPage = GraphForm.TabGraph.TabCount - 1
                        .PrintRange = IIf(ApplyToAllTabs, Printing.PrintRange.AllPages, Printing.PrintRange.CurrentPage)
                    Else
                        .ToPage = Layout.PageContents.Count
                        .PrintRange = IIf(.ToPage > 1, Printing.PrintRange.AllPages, Printing.PrintRange.CurrentPage)
                    End If
                End With

                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    PrintDoc = .Document
                    With PrintDoc.PrinterSettings
                        Select Case .PrintRange
                            Case Printing.PrintRange.AllPages
                                MinPageNum = 1
                                MaxPageNum = IIf(Layout.AutoAssign, TabGraph.TabCount - 1, Layout.PageContents.Count)
                            Case Printing.PrintRange.CurrentPage
                                MinPageNum = TabGraph.SelectedIndex + 1
                                MaxPageNum = MinPageNum
                            Case Printing.PrintRange.SomePages
                                MinPageNum = .FromPage
                                MaxPageNum = .ToPage
                        End Select
                    End With
                    CurrentPageNum = MinPageNum
                    PrintDoc.DocumentName = GroupFileName
                    PrintDoc.Print()
                End If
                .Dispose()
            End With

        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFilePrintSetup_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuFilePrintSetup.Click
        With New frmLayout
            .DefaultLayoutName = ActiveLayoutName
            .chkHide.Visible = False
            .ShowDialog(Me)
            .Dispose()
        End With
    End Sub

    Private Sub mnuFileSaveGroup_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileSaveGroup.Click
        If String.IsNullOrEmpty(GroupFileName) Then
            mnuFileSaveGroupAs.PerformClick()
        Else
            SaveSettings(GroupFileName)
        End If
    End Sub

    Private Sub mnuFileSaveGroupAs_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileSaveGroupAs.Click
        SaveAs()
    End Sub

    ''' <summary>
    ''' Save current graph settings to new .graph file
    ''' </summary>
    ''' <returns>True if user selected OK; False if Cancel</returns>
    Private Function SaveAs() As Boolean
        With New SaveFileDialog
            .AddExtension = True
            .CheckPathExists = True
            .DefaultExt = ".graph"
            .InitialDirectory = GetSetting(REGAPP, "General", "LastOpenDir", AppDataPath)
            .Filter = "Graph Settings File (*.graph)|*.graph"
            .OverwritePrompt = True
            .Title = "Save Graph Specifications"
            .FileName = GroupFileName
            If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                If .FileName = "" Then .Dispose() : Return False
                GroupFileName = .FileName
                SaveSetting(REGAPP, "General", "LastOpenDir", IO.Path.GetDirectoryName(GroupFileName))
            Else
                .Dispose()
                Return False
            End If
        End With
        SaveSettings(GroupFileName)

        ' Call sub to add this file as an MRU 
        mru.AddFile(GroupFileName)

        ResetTitleBar()
        Return True
    End Function

    ''' <summary>
    ''' If file has been modified, call this function to allow user to save graph settings file
    ''' </summary>
    ''' <returns>True is user selected Yes or No; False if he selected Cancel</returns>
    Private Function PromptSave() As Boolean
        Try
            If Me.TabGraph.TabCount = 2 AndAlso ActiveGraphTab.Series.Count = 0 Then Return True
            Select Case SaveChangesWarning(GroupFileName)
                Case Windows.Forms.DialogResult.Yes
                    If String.IsNullOrEmpty(GroupFileName) Then
                        Return SaveAs()
                    Else
                        SaveSettings(GroupFileName)
                        Return True
                    End If
                Case Windows.Forms.DialogResult.No : Return True
                Case Windows.Forms.DialogResult.Cancel : Return False
            End Select
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Function

    Private Sub mnuGraphDateTime_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuGraphDateTime.Click
        Try
            With ActiveGraphTab()
                Dim ai As clsAnimationInfo = .AnimationInfo
                If .GraphType = enumGraphType.Profile Then
                    Dim s As String = ""
                    Do
                        s = InputBox("Enter the date and time at which you wish to display the profile data:", "Profile Date-Time", ai.DateTime.ToString(MyDateTimeFormat))
                    Loop Until s = "" Or IsDate(s)
                    If s <> "" Then ai.DateTime = CDate(s)
                    .SetSeriesDateTime(ai.DateTime)
                Else
                    With New frmSelectDate
                        If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                        End If
                        .Dispose()
                    End With
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuGraphIntervals_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuGraphIntervals.Click
        Try
            With ActiveGraphTab()
                Dim ai As clsAnimationInfo = .AnimationInfo
                If .GraphType = enumGraphType.Histogram Then
                    Dim s As String = ai.NumIntervals
                    Do
                        s = InputBox("Enter the number of histogram intervals (bins) you want to use:", "Histogram Intervals", ai.NumIntervals)
                    Loop Until s = "" Or IsNumeric(s)
                    If s <> "" Then ai.NumIntervals = CInt(s)
                    For Each ser As clsSeriesHistogram In .Series
                        ser.NumIntervals = ai.NumIntervals
                        ser.GetData()
                    Next
                    ActiveGraphTab.ZoomExtents()
                    .Zed.AxisChange()
                    .Zed.Refresh()
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuGraphPlotVersus_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuGraphPlotVersus.DropDownItemClicked, tbPlotVersus.DropDownItemClicked
        Try
            Dim Index As Integer = CType(sender, ToolStripDropDownItem).DropDownItems.IndexOf(e.ClickedItem)
            With ActiveGraphTab()
                CheckDropDownItem(mnuGraphPlotVersus, Index)
                CheckDropDownItem(tbPlotVersus, Index)
                .ProfileXPlot = Index
                mnuGraphRMileRange.Enabled = .ProfileXPlot = clsGraphTab.enumProfileXPlot.RiverMile
                tbRMileRange.Enabled = .ProfileXPlot = clsGraphTab.enumProfileXPlot.RiverMile
                Dim xmin As Double
                For Each ser As clsSeriesLongProfile In .Series
                    ser.ProfXPlot = .ProfileXPlot
                    ser.GetData()
                    If ser.ZedCurve.Points.Count > 0 Then xmin = ser.ZedCurve.Points(0).X
                Next
                'reset x values for hidden curves used to maintain consistent y-axis scaling

                For Each crv As ZedGraph.LineItem In .Zed.GraphPane.CurveList
                    If crv.Label.Text = "HIDDEN" Then
                        crv.Points(0).X = xmin
                        crv.Points(1).X = xmin
                    End If
                Next

                If clsAxis.AxisExtra(.Zed.GraphPane.XAxis.Tag).AutoTitle Then
                    .Zed.GraphPane.XAxis.Title.Text = Choose(.ProfileXPlot + 1, "River Mile", "Segment Number")
                End If
                ResetAnimationLimits()
                EnableMenus()
                EnableGraphMenus()
                .ResetProfileScales()
                .Zed.AxisChange()
                .Zed.Refresh()
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuGraphRMileRange_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuGraphRMileRange.DropDownItemClicked, tbRMileRange.DropDownItemClicked
        Try
            Dim Index As Integer = CType(sender, ToolStripDropDownItem).DropDownItems.IndexOf(e.ClickedItem)
            With ActiveGraphTab.Zed.GraphPane.XAxis.Scale
                .MinAuto = False
                .MaxAuto = False
                .Min = .Max - RMRange(Index)
            End With
            CheckDropDownItem(mnuGraphRMileRange, Index)
            CheckDropDownItem(tbRMileRange, Index)
            ActiveGraphTab.Zed.GraphPane.AxisChange()
            ActiveGraphTab.Zed.Refresh()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuGraphTimeRange_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuGraphTimeRange.DropDownItemClicked, tbTimeRange.DropDownItemClicked
        Try
            Dim Index As Integer = CType(sender, ToolStripDropDownItem).DropDownItems.IndexOf(e.ClickedItem)
            With ActiveGraphTab.Zed.GraphPane.XAxis.Scale
                .MinAuto = False
                .MaxAuto = False
                .Max = .Min + TimeRange(Index) 'is OADate, so just add days
            End With
            CheckDropDownItem(mnuGraphTimeRange, Index)
            CheckDropDownItem(tbTimeRange, Index)
            ActiveGraphTab.Zed.GraphPane.AxisChange()
            ActiveGraphTab.Zed.Refresh()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuGraphTimeWindow_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuGraphTimeWindow.DropDownItemClicked, tbTimeWindow.DropDownItemClicked
        Try
            With ActiveGraphTab.AnimationInfo
                .TimeWindow = CType(sender, ToolStripDropDownItem).DropDownItems.IndexOf(e.ClickedItem)
                ActiveGraphTab.SetSeriesTimeWindow(.TimeWindow)
                CheckDropDownItem(mnuGraphTimeWindow, .TimeWindow)
                CheckDropDownItem(tbTimeWindow, .TimeWindow)
                ActiveGraphTab.Zed.Refresh()
                SetAnimationTimeStep(TimeWindow(.TimeWindow))
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuGraphType_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuGraphType.DropDownItemClicked, tbGraphType.DropDownItemClicked
        Dim GraphType As enumGraphType = CType(sender, ToolStripDropDownItem).DropDownItems.IndexOf(e.ClickedItem)
        If ChangeGraphType(GraphType) Then mnuToolsManage.PerformClick()
    End Sub

    Friend Function ChangeGraphType(ByVal GraphType As enumGraphType) As Boolean
        Try
            With ActiveGraphTab()
                If .Series.Count > 0 AndAlso Not ExpertMode AndAlso WarningMsg("Changing graph types will cause all existing series to be removed. Are you sure you want to continue?") = Windows.Forms.DialogResult.Cancel Then Return False
                .Series.Clear()
                .Zed.GraphPane.CurveList.Clear()
                .GraphType = GraphType
                '.Reset()
                LoadSettings()
                .ResetYAxes()
                .Zed.AxisChange()
                .Zed.Refresh()
                .Zed.GraphPane.Title.Text = ""
                .AnimationInfo.ToolbarVisible = False
                'automatically display animation toolbar if profile plot and one of the series is BMD type
                Select Case .GraphType
                    Case enumGraphType.Depth, enumGraphType.Profile, enumGraphType.Width
                        For Each tbl As clsTable In OpenTables
                            If tbl.TableType = clsTable.enumTableType.BMD Then
                                .AnimationInfo.ToolbarVisible = True
                                Exit For
                            End If
                        Next
                End Select
                EnableMenus()
                EnableGraphMenus()
                Application.DoEvents()
            End With
            CheckDropDownItem(mnuGraphType, GraphType)
            CheckDropDownItem(tbGraphType, GraphType)
            _IsModified = True
            Return True
        Catch ex As Exception
            ErrorMsg(, ex)
            Return False
        End Try
    End Function

    Private Sub mnuToolbarAnim_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuToolbarAnim.CheckedChanged, mnuTbAnim.CheckedChanged
        mnuToolbarAnim.Checked = CType(sender, ToolStripMenuItem).Checked
        mnuTbAnim.Checked = CType(sender, ToolStripMenuItem).Checked
        tbAnim.Visible = mnuToolbarAnim.Checked
        If ActiveGraphTab() IsNot Nothing Then ActiveGraphTab.AnimationInfo.ToolbarVisible = mnuToolbarAnim.Checked
        If tbAnim.Visible AndAlso Not CheckAnimationBMDSeries() Then Exit Sub
    End Sub

    Private Sub mnuToolbarMain_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuToolbarMain.CheckedChanged, mnuTbMain.CheckedChanged
        mnuToolbarMain.Checked = CType(sender, ToolStripMenuItem).Checked
        mnuTbMain.Checked = CType(sender, ToolStripMenuItem).Checked
        tbMain.Visible = mnuToolbarMain.Checked
    End Sub

    Private Sub mnuToolbarStatus_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuToolbarStatus.CheckedChanged, mnuTbStatus.CheckedChanged
        mnuToolbarStatus.Checked = CType(sender, ToolStripMenuItem).Checked
        mnuTbStatus.Checked = CType(sender, ToolStripMenuItem).Checked
        statusMain.Visible = mnuToolbarStatus.Checked
    End Sub

    Private Sub mnuToolbarText_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuToolbarText.CheckedChanged, mnuTbText.CheckedChanged
        mnuToolbarText.Checked = CType(sender, ToolStripMenuItem).Checked
        mnuTbText.Checked = CType(sender, ToolStripMenuItem).Checked
        For Each tbBtn As ToolStripItem In tbMain.Items
            If Not TypeOf tbBtn Is ToolStripSeparator Then
                With CType(tbBtn, Object)
                    If mnuToolbarText.Checked Then
                        .AutoSize = False
                        .height = 33
                        .Width = 44
                        .DisplayStyle = ToolStripItemDisplayStyle.ImageAndText
                    Else
                        .AutoSize = True
                        .DisplayStyle = ToolStripItemDisplayStyle.Image
                    End If
                End With
            End If
        Next
    End Sub

    Private Sub mnuToolsManage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuToolsManage.Click
        ManageSeries(False)
    End Sub

    Friend Sub ManageSeries(ByVal ShowOpen As Boolean)
        With New frmSeries
            .ShowOpen = ShowOpen
            .ShowDialog(Me)
            Application.DoEvents()
            ResetAnimationLimits()
            SetTabTooltip()
            If TableForm IsNot Nothing Then TableForm.Refresh()
            If StatsForm IsNot Nothing Then StatsForm.Refresh()
            EnableMenus()
            EnableGraphMenus()
            FillSeriesList()
            SetAxisProperties()
            _IsModified = True
            .Dispose()
            If tbAnim.Visible Then ResetAnimationLimits()
        End With
    End Sub

    Private Sub mnuToolsOptions_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuToolsOptions.Click
        With New frmOptions()
            .ShowDialog(Me)
        End With
    End Sub

    Private Sub mnuView_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuView.DropDownItemClicked
        Try
            With ActiveGraphTab.Zed
                If e.ClickedItem Is mnuViewCopy Then
                    .Copy(False)
                ElseIf e.ClickedItem Is mnuViewRefresh Then
                    ActiveGraphTab.Refresh()
                ElseIf e.ClickedItem Is mnuViewZoomPrev Then
                    ActiveGraphTab.ZoomPrevious()
                ElseIf e.ClickedItem Is mnuViewZoomLimits Then
                    ActiveGraphTab.ZoomLimits()
                ElseIf e.ClickedItem Is mnuViewZoomAll Then
                    ActiveGraphTab.ZoomExtents()
                ElseIf e.ClickedItem Is mnuViewAnimate Then
                    If Not mnuViewAnimate.Checked Then tbAnim.Visible = True
                    If tbAnim.Visible AndAlso Not CheckAnimationBMDSeries() Then Exit Sub
                    tbAnimPlay.Checked = Not mnuViewAnimate.Checked
                    AnimTimer.Enabled = Not mnuViewAnimate.Checked
                ElseIf e.ClickedItem Is mnuViewGridlines Then
                    .GraphPane.XAxis.MajorGrid.IsVisible = Not mnuViewGridlines.Checked
                    .GraphPane.XAxis.MinorGrid.IsVisible = Not mnuViewGridlines.Checked
                    .GraphPane.YAxis.MajorGrid.IsVisible = Not mnuViewGridlines.Checked
                    .GraphPane.YAxis.MinorGrid.IsVisible = Not mnuViewGridlines.Checked
                    .Refresh()
                ElseIf e.ClickedItem Is mnuViewLegend Then
                    .GraphPane.Legend.IsVisible = Not mnuViewLegend.Checked
                    .Refresh()
                ElseIf e.ClickedItem Is mnuViewData Then
                    If TableForm Is Nothing Then TableForm = New frmTable
                    TableForm.SetGraphTab(ActiveGraphTab)
                    TableForm.Show(Me)
                    TableForm.BringToFront()
                ElseIf e.ClickedItem Is mnuViewStats Then
                    If StatsForm Is Nothing Then StatsForm = New frmStats
                    StatsForm.Show(Me)
                    StatsForm.BringToFront()
                End If
            End With
            ToolTip.Active = Not AnimTimer.Enabled
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub RecentFileHandler(ByVal Number As Integer, ByVal FileName As String)
        TabGraph.Enabled = False
        splitMain.Enabled = False
        tbMain.Enabled = False
        mnuMain.Enabled = False
        Try
            GroupFileName = FileName
            LoadSettings(FileName)
        Catch ex As Exception
            GroupFileName = ""
        Finally
            TabGraph.Enabled = True
            splitMain.Enabled = True
            tbMain.Enabled = True
            mnuMain.Enabled = True
        End Try

        ' Call sub to reorder the MRU list
        mru.AddFile(FileName)
        mru.SaveToRegistry()
        ResetTitleBar()
    End Sub

    Private Sub mnuFileMovie_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuFileMovie.Click
        Dim aviMgr As AviFile.AviManager = Nothing
        Dim MovieFile As String = ""
        Dim Success As Boolean = False
        Try
            With New SaveFileDialog
                .FileName = IO.Path.ChangeExtension(GroupFileName, ".avi")
                .AddExtension = True
                .CheckPathExists = True
                .CreatePrompt = False
                .DefaultExt = ".avi"
                .Filter = "Movie File (*.avi)|*.avi"
                .FilterIndex = 0
                .OverwritePrompt = True
                .Title = "Create Animation Movie Starting at Current Timestep"
                .ValidateNames = True
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then MovieFile = .FileName
                .Dispose()
            End With

            If MovieFile = "" Then Exit Sub
            Dim msg As String = "; it might be open by another application. If the prior attempt to save the movie file caused an error to occur, you may need to restart the application."

            Try
                If My.Computer.FileSystem.FileExists(MovieFile) Then My.Computer.FileSystem.DeleteFile(MovieFile)
            Catch ex As Exception
                ErrorMsg("Unable to delete old video file" & msg, ex)
                Exit Sub
            End Try

            With trkAnim

                'will start from current position (unless is at end, when will start at beginning)

                If .Value = .Maximum Then .Value = .Minimum

                Try
                    aviMgr = New AviFile.AviManager(MovieFile, False)
                Catch ex As Exception
                    ErrorMsg("Unable to create new video file" & msg, ex)
                    Exit Sub
                End Try

                Dim aviStr As AviFile.VideoStream = Nothing

                tbAnim.Visible = True

                tbAnimBeg.Enabled = False
                tbAnimEnd.Enabled = False
                tbAnimNext.Enabled = False
                tbAnimPrev.Enabled = False
                tbAnimSpeed.Enabled = False
                tbAnimPause.Enabled = False
                tbAnimPlay.Enabled = False

                Do
                    Application.DoEvents()
                    If aviStr Is Nothing Then
                        Try
                            Dim framerate As Double = Choose(ActiveGraphTab.AnimationInfo.Speed, 2.4, 3, 4.8, 8, 12) 'determined empirically
                            aviStr = aviMgr.AddVideoStream(False, framerate, ActiveGraphTab.Zed.GetImage) 'set first argument to true to show dialog to select codec--many don't work, so I disabled
                        Catch ex As Exception
                            ErrorMsg("Unable to create new video stream" & msg, ex)
                            Exit Sub
                        End Try
                    Else
                        aviStr.AddFrame(ActiveGraphTab.Zed.GetImage)
                    End If
                    If .Value + .TickFrequency > .Maximum Then Exit Do
                    .Value += .TickFrequency
                    If Not tbAnim.Visible Then Success = True : Exit Sub 'user clicks on "X" of animation toolbar to stop avi capture
                Loop

                .Value = .Minimum
                Success = True
            End With

        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            tbAnimBeg.Enabled = True
            tbAnimEnd.Enabled = True
            tbAnimNext.Enabled = True
            tbAnimPrev.Enabled = True
            tbAnimSpeed.Enabled = True
            tbAnimPause.Enabled = True
            tbAnimPlay.Enabled = True
            If aviMgr IsNot Nothing Then aviMgr.Close()
            tbAnim.Visible = True
            If Success And Not String.IsNullOrEmpty(MovieFile) Then Process.Start(MovieFile)
        End Try
    End Sub

    ''' <summary>
    ''' Reset animation limits for all series (min/max times for trackbar); called when series are managed
    ''' </summary>
    Friend Sub ResetAnimationLimits()
        Dim dr As DbDataReader = Nothing
        Try
            If ActiveGraphTab() Is Nothing Then Exit Sub
            With ActiveGraphTab()
                If .Series.Count = 0 Or Not .AnimationInfo.ToolbarVisible Then Exit Sub

                If .GraphType = enumGraphType.TimeSeries Then
                    Dim MaxNode As Integer = 0
                    For Each ser As clsSeries In ActiveGraphTab.Series
                        If Not ser.IsCalc AndAlso ser.Table.TableType = clsTable.enumTableType.BMD Then
                            MaxNode = Math.Max(MaxNode, ser.Table.GetStationList("All Branches").Count - 1)
                        End If
                    Next
                    For Each ser As clsSeries In ActiveGraphTab.Series
                        If Not ser.IsCalc AndAlso ser.Table.TableType = clsTable.enumTableType.BMD Then
                            With ActiveGraphTab.AnimationInfo
                                .MaxNode = MaxNode
                                For i As Integer = 0 To ser.Table.GetStationList("All Branches").Count - 1
                                    If StringSplit(ser.Table.GetStationList("All Branches")(i), " - ")(0) = ser.StationID Then
                                        .NodeNum = i
                                        Exit For
                                    End If
                                Next
                            End With
                            'If .GraphOptions.AutoGraphTitle Then .Zed.GraphPane.Title.Text = String.Format("Station ID: {0}", ser.StationID)
                            Exit For
                        End If
                    Next
                    '.Zed.GraphPane.Title.IsVisible = True
                    With trkAnim
                        .SmallChange = 1 / (MaxNode + 1) * (.Maximum - .Minimum)
                        .LargeChange = .SmallChange * 10
                        .TickFrequency = .SmallChange
                        If ActiveGraphTab.AnimationInfo.MaxNode <> 0 Then .Value = ActiveGraphTab.AnimationInfo.NodeNum / ActiveGraphTab.AnimationInfo.MaxNode * (.Maximum - .Minimum)
                    End With
                Else
                    Dim MinDate As Date = Date.MaxValue
                    Dim MaxDate As Date = Date.MinValue
                    Dim TimeStep As Integer = 60
                    For Each ser As clsSeries In ActiveGraphTab.Series
                        If Not ser.IsCalc Then
                            If ser.Table.TableType = clsTable.enumTableType.BMD Then
                                Dim StartDate As Date = ser.Table.dsBMD.Time(0)
                                If StartDate < MinDate Then MinDate = StartDate
                                Dim EndDate As Date = ser.Table.dsBMD.Time(ser.Table.dsBMD.NumTimes - 1)
                                If EndDate > MaxDate Then MaxDate = EndDate
                                TimeStep = ser.Table.dsBMD.Time(1).Subtract(ser.Table.dsBMD.Time(0)).TotalMinutes
                            Else
                                Dim StartDate, EndDate As Date
                                Dim sql As String = String.Format("SELECT MIN(Date_Time) as MinDate,MAX(Date_Time) as MaxDate FROM {0} WHERE PCode='{1}'", ser.Table.TableName, ser.PCode)
                                Select Case .GraphType
                                    Case enumGraphType.Depth : sql &= String.Format("AND STATION_ID='{0}' AND DEPTH_M IS NOT NULL", ser.StationID)
                                    Case enumGraphType.Width : sql &= String.Format("AND STATION_ID='{0}' AND LEW_PCT IS NOT NULL", ser.StationID)
                                    Case Else
                                End Select
                                dr = ser.Table.WRDBProject.DB.ExecuteReader(sql)
                                If dr IsNot Nothing AndAlso dr.Read AndAlso Not dr.IsDBNull(0) AndAlso Not dr.IsDBNull(1) Then
                                    StartDate = dr.GetDateTime(0)
                                    EndDate = dr.GetDateTime(1)
                                End If
                                dr.Close()
                                If StartDate < MinDate Then MinDate = StartDate
                                If EndDate > MaxDate Then MaxDate = EndDate
                                If .GraphType = enumGraphType.Profile Then
                                    TimeStep = TimeWindow(CType(ser, clsSeriesLongProfile).TimeWindow)
                                ElseIf .GraphType = enumGraphType.Depth Then
                                    TimeStep = TimeWindow(CType(ser, clsSeriesDepthProfile).TimeWindow)
                                ElseIf .GraphType = enumGraphType.Width Then
                                    TimeStep = TimeWindow(CType(ser, clsSeriesWidthProfile).TimeWindow)
                                ElseIf .GraphType = enumGraphType.Scatter Then
                                    TimeStep = TimeWindow(CType(ser, clsSeriesScatter).TimeWindow)
                                End If
                            End If
                        End If
                    Next
                    With .AnimationInfo
                        .MinDate = MinDate
                        .MaxDate = MaxDate
                        If .DateTime < MinDate Then .DateTime = MinDate
                        .TimeStep = TimeStep
                        SetAnimationTimeStep(.TimeStep)
                        trkAnim.Value = Math.Max(trkAnim.Minimum, Math.Min(trkAnim.Maximum, .DateTime.Subtract(.MinDate).TotalMinutes / .MaxDate.Subtract(.MinDate).TotalMinutes * (trkAnim.Maximum - trkAnim.Minimum)))
                    End With
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            If dr IsNot Nothing Then dr.Close()
        End Try
    End Sub

    ''' <summary>
    ''' Enable items on Graph menu based on the graph type
    ''' </summary>
    Friend Sub EnableGraphMenus()
        Try
            If ActiveGraphTab() Is Nothing Then Exit Sub

            mnuGraphTimeRange.Visible = False
            tbTimeRange.Visible = False
            mnuGraphRMileRange.Visible = False
            tbRMileRange.Visible = False
            mnuGraphTimeWindow.Visible = False
            tbTimeWindow.Visible = False
            mnuGraphDateTime.Visible = False
            tbDateTime.Visible = False
            mnuGraphPlotVersus.Visible = False
            tbPlotVersus.Visible = False
            mnuGraphIntervals.Visible = False
            tbIntervals.Visible = False

            Select Case ActiveGraphTab.GraphType
                Case enumGraphType.TimeSeries
                    mnuGraphTimeRange.Visible = True
                    tbTimeRange.Visible = True
                    mnuViewAnimate.Enabled = True
                    mnuViewAnimateSpeed.Enabled = True
                    'mnuToolbarAnim.Checked = False
                    mnuToolbarAnim.Enabled = True
                Case enumGraphType.Profile
                    mnuGraphRMileRange.Visible = True
                    tbRMileRange.Visible = True
                    mnuGraphDateTime.Visible = True
                    tbDateTime.Visible = True
                    mnuGraphTimeWindow.Visible = True
                    tbTimeWindow.Visible = True
                    mnuViewAnimate.Enabled = True
                    mnuViewAnimateSpeed.Enabled = True
                    mnuToolbarAnim.Enabled = True
                    mnuGraphPlotVersus.Visible = True
                    tbPlotVersus.Visible = True
                Case enumGraphType.Depth, enumGraphType.Width
                    mnuGraphDateTime.Visible = True
                    tbDateTime.Visible = True
                    mnuGraphTimeWindow.Visible = True
                    tbTimeWindow.Visible = True
                    mnuViewAnimate.Enabled = True
                    mnuViewAnimateSpeed.Enabled = True
                    mnuToolbarAnim.Enabled = True
                Case enumGraphType.Scatter
                    mnuGraphTimeWindow.Visible = True
                    tbTimeWindow.Visible = True
                Case enumGraphType.Histogram
                    mnuGraphIntervals.Visible = True
                    tbIntervals.Visible = True
            End Select

            'make menu items reflect currently selected graph
            With ActiveGraphTab()
                mnuViewGridlines.Checked = .Zed.GraphPane.XAxis.MajorGrid.IsVisible And .Zed.GraphPane.YAxis.MajorGrid.IsVisible
                mnuViewLegend.Checked = .Zed.GraphPane.Legend.IsVisible
                For i As Integer = 0 To mnuGraphType.DropDownItems.Count - 1
                    CType(mnuGraphType.DropDownItems(i), ToolStripMenuItem).Checked = (i = .GraphType)
                Next
                For i As Integer = 0 To tbGraphType.DropDownItems.Count - 1
                    CType(tbGraphType.DropDownItems(i), ToolStripMenuItem).Checked = (i = .GraphType)
                Next
                Select Case .GraphType
                    Case enumGraphType.TimeSeries
                        For i As Integer = 0 To TimeRange.Length - 1
                            With .Zed.GraphPane.XAxis.Scale
                                CType(mnuGraphTimeRange.DropDownItems(i), ToolStripMenuItem).Checked = (Math.Abs((.Max - .Min) - TimeRange(i) / 24) < 0.001)
                                CType(tbTimeRange.DropDownItems(i), ToolStripMenuItem).Checked = (Math.Abs((.Max - .Min) - TimeRange(i) / 24) < 0.001)
                            End With
                        Next
                    Case enumGraphType.Profile
                        For i As Integer = 0 To RMRange.Length - 1
                            With .Zed.GraphPane.XAxis.Scale
                                CType(mnuGraphRMileRange.DropDownItems(i), ToolStripMenuItem).Checked = (Math.Abs((.Max - .Min) - RMRange(i) / 24) < 0.001)
                                CType(tbRMileRange.DropDownItems(i), ToolStripMenuItem).Checked = (Math.Abs((.Max - .Min) - RMRange(i) / 24) < 0.001)
                            End With
                        Next
                        If .Series.Count > 0 Then 'make menu match window for first series (all should be the same)
                            CheckDropDownItem(mnuGraphTimeWindow, CType(.Series(0), clsSeriesLongProfile).TimeWindow)
                            CheckDropDownItem(tbTimeWindow, CType(.Series(0), clsSeriesLongProfile).TimeWindow)
                            ResetAnimationLimits()
                            SetAnimationTimeStep(TimeWindow(CType(.Series(0), clsSeriesLongProfile).TimeWindow))
                        End If
                        CheckDropDownItem(mnuGraphPlotVersus, .ProfileXPlot)
                        CheckDropDownItem(tbPlotVersus, .ProfileXPlot)
                    Case enumGraphType.Depth
                        If .Series.Count > 0 Then 'make menu match window for first series (all should be the same)
                            CheckDropDownItem(mnuGraphTimeWindow, CType(.Series(0), clsSeriesDepthProfile).TimeWindow)
                            CheckDropDownItem(tbTimeWindow, CType(.Series(0), clsSeriesDepthProfile).TimeWindow)
                        End If
                    Case enumGraphType.Depth, enumGraphType.Width
                        If .Series.Count > 0 Then 'make menu match window for first series (all should be the same)
                            CheckDropDownItem(mnuGraphTimeWindow, CType(.Series(0), clsSeriesWidthProfile).TimeWindow)
                            CheckDropDownItem(tbTimeWindow, CType(.Series(0), clsSeriesWidthProfile).TimeWindow)
                        End If
                End Select
                'set animation info
                With .AnimationInfo
                    tbAnim.Visible = .ToolbarVisible
                End With
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Set the timestep to use for animation
    ''' </summary>
    ''' <param name="TimeStepMin">The size of the timestep in minutes (if 0, will step from one BMD time to the next)</param>
    Private Sub SetAnimationTimeStep(ByVal TimeStepMin As Integer)
        Try
            If ActiveGraphTab.GraphType = enumGraphType.TimeSeries Then Exit Sub
            With ActiveGraphTab.AnimationInfo
                If Not .ToolbarVisible Then Exit Sub
                .TimeStep = TimeStepMin
                Dim TimeSpan As Double = .MaxDate.Subtract(.MinDate).TotalMinutes
                If TimeSpan <> 0 Then
                    Try
                        With trkAnim
                            .SmallChange = TimeStepMin / TimeSpan * (.Maximum - .Minimum)
                            .LargeChange = .SmallChange * 10
                            .TickFrequency = .SmallChange
                        End With
                    Catch ex As Exception
                    End Try
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub SetTabTooltip()
        Exit Sub

        'Roy says these take up too much space!
        With TabGraph.SelectedTab
            .ToolTipText = ""
            For Each ser As clsSeries In ActiveGraphTab.Series
                .ToolTipText &= IIf(.ToolTipText = "", "", ", ") & ser.Label
            Next
            .ToolTipText = Choose(ActiveGraphTab.GraphType + 1, "Time Series", "Long. Profile", "Depth Profile") & ": " & .ToolTipText
        End With
    End Sub

#Region "Load and save to ini file (.Graph)"

    ''' <summary>
    ''' Load default graph formatting settings
    ''' </summary>
    ''' <remarks></remarks>
    Friend Sub LoadSettings()
        Reset()
        Dim DefaultFile As String = My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData & "\Default.graph"
        LoadSettings(DefaultFile, True)
    End Sub

    ''' <summary>
    ''' Load settings from specified .Graph file
    ''' </summary>
    ''' <param name="FileName">Full path to .Graph file</param>
    ''' <param name="FormatOnly">True if want to load only formatting information</param>
    ''' <param name="NewFromTemplate">If true, will load template and offer to redefine tables if present</param>
    Friend Sub LoadSettings(ByVal FileName As String, Optional ByVal FormatOnly As Boolean = False, Optional ByVal NewFromTemplate As Boolean = False)
        Try
            _IsLoadCancelled = False
            statusMain.Cursor = Cursors.Arrow
            If Not FormatOnly Then WriteProgress(Me, "Loading from {0}...", FileName)

            Dim ini As New WRDB.IniFile.clsIniFile(FileName, True)
            Dim section As String

            If Not FormatOnly Then
                'load print layouts
                ActiveLayoutName = ini.GetKeyText("Layouts", "ActiveLayoutName", "Default")
                Dim NumLayouts As Integer = ini.GetKeyText("Layouts", "NumLayouts", 0)
                For l As Integer = 0 To NumLayouts - 1
                    section = "Layout" & l
                    Dim Name As String = ini.GetKeyText(section, "Name", "")
                    Dim Layout As New clsLayout(Name)
                    With Layout
                        .NumRows = ini.GetKeyText(section, "NumRows", .NumRows)
                        .NumCols = ini.GetKeyText(section, "NumCols", .NumCols)
                        .AutoAssign = ini.GetKeyText(section, "AutoAssign", .AutoAssign)
                        .Landscape = ini.GetKeyText(section, "Landscape", .Landscape)
                        .Margins.Left = ini.GetKeyText(section, "Margin_Left", .Margins.Left)
                        .Margins.Right = ini.GetKeyText(section, "Margin_Right", .Margins.Right)
                        .Margins.Top = ini.GetKeyText(section, "Margin_Top", .Margins.Top)
                        .Margins.Bottom = ini.GetKeyText(section, "Margin_Bottom", .Margins.Bottom)
                        .RowColMargin = ini.GetKeyText(section, "Margin_RowCol", .RowColMargin)
                        .DrawBorders = ini.GetKeyText(section, "DrawBorders", .DrawBorders)
                        Dim NumPages As Integer = ini.GetKeyText(section, "NumPages", 1)
                        .PageContents.Clear()
                        For p As Integer = 0 To NumPages - 1
                            .PageContents.Add(New clsPaneContents)
                            For r As Integer = 0 To clsLayout.MaxRows - 1
                                For c As Integer = 0 To clsLayout.MaxCols - 1
                                    .PageContents(p).Item(c, r) = ini.GetKeyText(section, String.Format("Page{0}_Pane_C{1}R{2}", p, c, r), "None")
                                Next
                            Next
                        Next
                    End With
                    If Layouts.ContainsKey(Name) Then Layouts(Name) = Layout Else Layouts.Add(Name, Layout)
                Next
            End If

            'databases and/or tables may be reselected if not found, and the wrdb project name would change such that series would lose their connections
            'key strings contain original project name; values strings contain tab-separated datasource and tablename
            Dim RenamedProjects As New Generic.Dictionary(Of String, String)

            ApplyToAllTabs = ini.GetKeyText("Graphs", "ApplyToAll", ApplyToAllTabs)
            mnuTabGraphApplyAll.Checked = ApplyToAllTabs

            Dim NumTables As Integer = ini.GetKeyText("Tables", "NumTables", 0)

            If FormatOnly Or (NewFromTemplate And NumTables = 0) Then 'apply formats to all existing tabs (and series)
                Dim NumGraphs As Integer = ini.GetKeyText("Graphs", "NumGraphs", 1) 's/b only 1
                For t As Integer = 0 To NumGraphs - 1
                    With TabGraph
                        With ActiveGraphTab(TabGraph.SelectedIndex)
                            section = "Graph" & t
                            .Zed.IsShowPointValues = ini.GetKeyText(section, "ShowPointValues", True)
                            .ProfileXPlot = ini.GetKeyText(section, "ProfileXPlot", clsGraphTab.enumProfileXPlot.RiverMile)
                            .Reset()
                            EnableMenus()
                            EnableGraphMenus()

                            .ProfileXPlot = ini.GetKeyText(section, "ProfileXPlot", clsGraphTab.enumProfileXPlot.RiverMile)
                            .AnimationInfo.TimeStep = ini.GetKeyText(section, "TimeStep", 60)

                            With .GraphOptions
                                .GraphTitle = ini.GetKeyText(section, "Title", "")
                                .AutoGraphTitle = ini.GetKeyText(section, "AutoTitle", True)
                                LoadFont(.TitleFont, ini, section, "Title")
                                '.GraphBorder = ini.GetKeyText(section, "GraphBorder", False)
                                .UseFontScaleFactor = ini.GetKeyText(section, "UseFontScaleFactor", True)

                                .LegendPos = ini.GetKeyText(section, "LegendPosition", LegendPos.BottomCenter)
                                .LegendVisible = ini.GetKeyText(section, "LegendVisible", True)
                                .LegendBorder = ini.GetKeyText(section, "LegendBorder", True)
                                LoadFont(.LegendFont, ini, section, "Legend")

                                .NoteText = ini.GetKeyText(section, "Notes", "")
                                .NoteVisible = ini.GetKeyText(section, "NoteVisible", True)
                                .NotePosition = ini.GetKeyText(section, "NotePosition", enumNotePosition.TopRight)
                                .NoteAlignment = ini.GetKeyText(section, "NoteAlignment", enumNoteAlignment.Center)
                                .NoteBorder = ini.GetKeyText(section, "NoteBorder", True)
                                LoadFont(.NoteFont, ini, section, "Note")

                                .FillColor = Color.FromName(ini.GetKeyText(section, "BackgroundColor", System.Drawing.SystemColors.Info.Name))
                                .ZoomOption = ini.GetKeyText(section, "ZoomOption", enumZoomOptions.Auto)
                                .ScrollBars = ini.GetKeyText(section, "ScrollBars", False)
                                .ShowPoints = ini.GetKeyText(section, "ShowPoints", True)

                                'load default series formats and save for future when series are added
                                .DefaultSeriesFormats.Clear()
                                Dim NumSeries As Integer = ini.GetKeyText(section, "NumSeries", 0)

                                For i As Integer = 0 To NumSeries - 1
                                    section = "Graph" & t & "-Series" & i
                                    If ini.GetSectionNames.Contains(section) Then
                                        Dim ser As New clsSeriesTimeSeries(._Zed)
                                        With ser
                                            .SmoothCurve = ini.GetKeyText(section, "SmoothCurve", False)
                                            .LineColor = Color.FromName(ini.GetKeyText(section, "LineColor", .LineColor.Name))
                                            .LineType = ini.GetKeyText(section, "LineType", clsSeries.enumLineType.Solid)
                                            .LineWidth = ini.GetKeyText(section, "LineWidth", 1)
                                            .SymbolFill = ini.GetKeyText(section, "SymbolFill", False)
                                            .SymbolType = ini.GetKeyText(section, "SymbolType", .SymbolType)
                                            .SymbolBorderColor = Color.FromName(ini.GetKeyText(section, "SymbolBorderColor", .LineColor.Name))
                                            .SymbolFillColor = Color.FromName(ini.GetKeyText(section, "SymbolFillColor", .LineColor.Name))
                                            .SymbolSize = ini.GetKeyText(section, "SymbolSize", 6)
                                        End With
                                        .DefaultSeriesFormats.Add(ser)
                                    End If
                                Next
                            End With

                            With ActiveGraphTab()
                                If .GraphType = enumGraphType.TimeSeries Then
                                    For i As Integer = 0 To Math.Min(.Series.Count, .GraphOptions.DefaultSeriesFormats.Count) - 1
                                        Dim ser As clsSeriesTimeSeries = .GraphOptions.DefaultSeriesFormats(i)
                                        With .Series(i)
                                            .SmoothCurve = ser.SmoothCurve
                                            .LineColor = ser.LineColor
                                            .LineType = ser.LineType
                                            .LineWidth = ser.LineWidth
                                            .SymbolFill = ser.SymbolFill
                                            .SymbolType = ser.SymbolType
                                            .SymbolSize = ser.SymbolSize
                                            .SymbolBorderColor = ser.SymbolBorderColor
                                            .SymbolFillColor = ser.SymbolFillColor
                                        End With
                                    Next
                                End If
                            End With

                            'now load axis settings
                            For i As Integer = 1 To 2
                                Dim axis As New clsAxis(.Zed, Choose(i, clsAxis.enumAxis.XAxis, clsAxis.enumAxis.X2Axis), 0, ActiveGraphTab.GraphOptions.FontScaleFactor)
                                LoadAxis(axis, ini, String.Format("Graph{0}-XAxis{1}", t, i), True)
                                For j As Integer = 0 To 4
                                    axis = New clsAxis(.Zed, Choose(i, clsAxis.enumAxis.YAxis, clsAxis.enumAxis.Y2Axis), j, ActiveGraphTab.GraphOptions.FontScaleFactor)
                                    LoadAxis(axis, ini, String.Format("Graph{0}-YAxis{1}_{2}", t, i, j), True)
                                Next
                            Next

                            Dim tw As Integer = -1
                            For i As Integer = 0 To TimeWindow.Length - 1
                                If Math.Abs(TimeWindow(i) - .AnimationInfo.TimeStep) < 0.1 Then tw = i : Exit For
                            Next
                            If tw = -1 Then tw = 60
                            .SetSeriesTimeWindow(tw)
                            ResetAnimationLimits()
                            EnableMenus()
                            EnableGraphMenus()
                            If .GraphType = enumGraphType.Profile Then .ResetProfileScales()
                            .Zed.AxisChange()
                            .Zed.Refresh()
                        End With
                    End With
                Next t

            Else 'not formatonly--load tables, tabs and series

looptemplate:

                LoadingSettings = True
                'clear all tabs and open tables (except New... one)
                Dim tmax As Integer = TabGraph.TabCount - 2
                For t As Integer = tmax To 0 Step -1
                    ActiveGraphTab(t).Dispose()
                    TabGraph.TabPages.RemoveAt(t)
                Next
                For t As Integer = 0 To OpenTables.Count - 1
                    With OpenTables(t)
                        'need to dispose memory here?
                    End With
                Next
                OpenTables.Clear()
                GC.Collect()

                'load tables
                Dim TableError As String = ""

                Dim tblType(NumTables - 1) As clsTable.enumTableType
                Dim relPath(NumTables - 1) As String
                Dim dataSource(NumTables - 1) As String
                Dim tblName(NumTables - 1) As String
                Dim tblFile(NumTables - 1) As String
                Dim tblSQL(NumTables - 1) As String
                Dim projName(NumTables - 1) As String
                Dim projNameOrig(NumTables - 1) As String
                Dim calibration(NumTables - 1) As clsCalibration
                Dim TableProjectNameMissing As Boolean = False

                For i As Integer = 0 To NumTables - 1
                    section = "Table" & i
                    tblType(i) = ini.GetKeyText(section, "TableType", clsTable.enumTableType.Database)
                    relPath(i) = ini.GetKeyText(section, "RelativePath", "")
                    dataSource(i) = ini.GetKeyText(section, "DataSource", relPath(i))
                    tblName(i) = ini.GetKeyText(section, "TableName")
                    tblFile(i) = ini.GetKeyText(section, "TableFile")
                    tblSQL(i) = ini.GetKeyText(section, "SqlString")
                    projName(i) = ini.GetKeyText(section, "ProjectName", "")
                    calibration(i) = New clsCalibration("")
                    If tblType(i) = clsTable.enumTableType.Calibration Then calibration(i).LoadSettings(ini, section)
                    If projName(i) = "" Then 'for backwards compatibility
                        projNameOrig(i) = tblName(i)
                        TableProjectNameMissing = True
                    Else
                        projNameOrig(i) = projName(i) & vbTab & tblName(i) 'so can tell if some were reselected
                    End If
                Next i

                'if template, display tables in dialog and allow user to change them

                If NewFromTemplate And NumTables > 0 Then
                    With New frmVerifyTables
                        Dim dgvTables As New WRDB.Controls.DGVEditor(.dgTables)
                        dgvTables.SetHeadings("Table Type~Rel Path~DataSource~Table Name~Table File~Proj Name~Directory or Database Name~Table Name~Found~Browse...", False, 0)
                        dgvTables.SetColumnFormat(WRDB.Controls.DGVEditor.enumColumnTypes.CheckBox, 8)
                        dgvTables.SetColumnFormat(WRDB.Controls.DGVEditor.enumColumnTypes.Button, 9)
                        For i As Integer = 0 To 5
                            .dgTables.Columns(i).Visible = False
                        Next
                        .dgTables.Columns(6).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
                        .dgTables.Columns(6).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft
                        .dgTables.Columns(7).AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
                        .dgTables.Columns(7).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft
                        .dgTables.Columns(8).ValueType = GetType(Boolean)
                        .dgTables.Columns(8).ReadOnly = True
                        .dgTables.Columns(8).AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
                        .dgTables.Columns(9).AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells

                        With .dgTables
                            'the grid contains 8 columns; only last two are visible
                            For i As Integer = 0 To NumTables - 1
                                If tblType(i) <> clsTable.enumTableType.Calibration Then
                                    .Rows.Add(tblType(i), relPath(i), dataSource(i), tblName(i), tblFile(i), projName(i))
                                End If
                                Select Case tblType(i)
                                    Case clsTable.enumTableType.WRDB5, clsTable.enumTableType.WRDB4
                                        .Item(6, .RowCount - 1).Value = projName(i)
                                        .Item(7, .RowCount - 1).Value = tblName(i)
                                        '.Columns(8).Visible = False
                                        Dim tblTemp As New clsTable()
                                        If tblType(i) = clsTable.enumTableType.WRDB5 Then
                                            tblTemp.CreateWRDB5Table(projName(i))
                                        Else
                                            tblTemp.CreateWRDB4Table(projName(i))
                                        End If
                                        .Item(8, .RowCount - 1).Value = tblTemp IsNot Nothing AndAlso tblTemp.WRDBProject.DB.TableExists(tblName(i))
                                    Case clsTable.enumTableType.Folder
                                        .Item(6, .RowCount - 1).Value = dataSource(i)
                                        .Item(7, .RowCount - 1).Value = tblFile(i)
                                        .Item(8, .RowCount - 1).Value = My.Computer.FileSystem.FileExists(dataSource(i) & "\" & tblFile(i))
                                    Case clsTable.enumTableType.Database
                                        .Item(6, .RowCount - 1).Value = dataSource(i)
                                        .Item(7, .RowCount - 1).Value = tblFile(i)
                                        .Item(8, .RowCount - 1).Value = My.Computer.FileSystem.FileExists(dataSource(i))
                                    Case clsTable.enumTableType.WRDBData
                                        .Item(6, .RowCount - 1).Value = dataSource(i)
                                        .Item(7, .RowCount - 1).Value = "(All Files)"
                                        .Item(8, .RowCount - 1).Value = My.Computer.FileSystem.DirectoryExists(dataSource(i))
                                    Case clsTable.enumTableType.BMD
                                        .Item(6, .RowCount - 1).Value = IO.Path.GetDirectoryName(dataSource(i))
                                        .Item(7, .RowCount - 1).Value = IO.Path.GetFileName(dataSource(i))
                                        .Item(8, .RowCount - 1).Value = My.Computer.FileSystem.FileExists(dataSource(i))
                                    Case clsTable.enumTableType.Calibration
                                        'for now don't only allow user to replace files
                                End Select
                            Next
                        End With

                        WriteProgress(Me)

                        If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                            With .dgTables
                                Dim r As Integer = 0
                                For i As Integer = 0 To NumTables - 1
                                    If tblType(i) <> clsTable.enumTableType.Calibration Then
                                        tblType(i) = .Item(0, r).Value
                                        relPath(i) = .Item(1, r).Value
                                        dataSource(i) = .Item(2, r).Value
                                        tblName(i) = .Item(3, r).Value
                                        tblFile(i) = .Item(4, r).Value
                                        projName(i) = .Item(5, r).Value
                                        tblSQL(i) = "" 'must remove all references to SQL if reselect table
                                        r += 1
                                    End If
                                Next
                            End With
                        Else 'assume cancel means you don't want to use template after all
                            With TabGraph
                                For i As Integer = .TabCount - 2 To 0 Step -1
                                    .TabPages.RemoveAt(i)
                                Next
                                .TabPages.Insert(0, "")
                                AddGraphTab(.TabPages(0))
                                .SelectedIndex = 0
                            End With
                            Exit Sub
                        End If
                        .Dispose()
                    End With
                End If

                'load all tables based on specification in ini file or as redefined for template file

                For i As Integer = 0 To NumTables - 1
                    section = "Table" & i
                    Dim tbl As New clsTable(GroupFileName, ExpertMode)
                    With tbl
                        WriteProgress(Me, i, NumTables - 1, "Loading table: {0} (click status bar to cancel)...", tblName(i))
                        If _IsLoadCancelled Then Exit Try
                        Select Case tblType(i)
                            Case clsTable.enumTableType.WRDB5
                                If Not .CreateWRDB5Table(projName(i)) Then TableError &= projName(i) & "\n" : Continue For
                                .CreateTempData()
                            Case clsTable.enumTableType.WRDB4
                                If Not .CreateWRDB4Table(projName(i)) Then TableError &= projName(i) & "\n" : Continue For
                            Case clsTable.enumTableType.BMD
                                Dim BMDFile As String = dataSource(i)
                                If Not .CreateBMDTable(BMDFile, relPath(i)) Then TableError &= BMDFile & "\n" : Continue For
                            Case clsTable.enumTableType.WRDBData
                                Dim LSPCFile As String = dataSource(i)
                                If Not .CreateWRDBDataTable(LSPCFile, relPath(i)) Then TableError &= LSPCFile & "\n" : Continue For
                            Case clsTable.enumTableType.Database
                                If Not .CreateDatabaseTable(dataSource(i), tblFile(i), relPath(i)) Then TableError &= dataSource(i) & tblFile(i) & "\n" : Continue For
                            Case clsTable.enumTableType.Folder
                                If Not .CreateDatabaseTable(dataSource(i), tblFile(i), relPath(i)) Then TableError &= dataSource(i) & tblFile(i) & "\n" : Continue For
                            Case clsTable.enumTableType.Calibration
                                If Not .CreateCalibrationTable(calibration(i)) Then TableError &= calibration(i).Name & "\n" : Continue For
                            Case clsTable.enumTableType.External
                                If Not .CreateExternalTable(dataSource(i), tblFile(i)) Then Continue For
                            Case Else
                                Throw New ApplicationException("Invalid TableType encountered: " & tblType(i))
                        End Select
                        .TableName = tblName(i)
                        If .IsConvertedDB Then .TableName = "[" & IO.Path.GetFileNameWithoutExtension(.TableFile) & "#TXT]" 'older versions didn't store correct table name for new way of reading data
                        .SqlString = tblSQL(i)
                        If Not RenamedProjects.ContainsKey(projNameOrig(i)) Then RenamedProjects.Add(projNameOrig(i), .ProjectName & vbTab & .TableName)
                    End With
                    OpenTables.Add(tbl)
                Next i
                WriteProgress(Me)

                If TableError <> "" AndAlso WarningMsg("One or more data tables or WRDB Projects identified in the .Graph file could not be loaded:\n\n{0}\nDo you want to browse to select the missing data tables?\n\nIf you click 'Cancel', all series associated with the missing tables will be omitted.", TableError.Replace("#", ".").Replace("\n", vbCr).Replace("\", "/")) = Windows.Forms.DialogResult.OK Then NewFromTemplate = True : GoTo looptemplate

                Dim NumGraphs As Integer = ini.GetKeyText("Graphs", "NumGraphs", 1)
                For t As Integer = 0 To NumGraphs - 1
                    With TabGraph
                        If t > .TabCount - 2 Then 'add another tab
                            LoadingSettings = True
                            .TabPages.Insert(.TabCount - 1, "Graph " & .TabCount - 1)
                            AddGraphTab(.TabPages(.TabCount - 2))
                            .SelectedIndex = .TabCount - 2
                            .TabPages(.TabCount - 2).ImageIndex = 0
                            ResetAnimationLimits()
                            ActiveGraphTab.Reset()
                            SetTabTooltip()
                        End If
                        With ActiveGraphTab(t)
                            section = "Graph" & t
                            .Name = ini.GetKeyText(section, "Name", "Graph " & t + 1)
                            TabGraph.SelectedTab.Text = .Name
                            .GraphType = ini.GetKeyText(section, "GraphType", enumGraphType.TimeSeries)
                            .Zed.IsShowPointValues = ini.GetKeyText(section, "ShowPointValues", True)
                            .ProfileXPlot = ini.GetKeyText(section, "ProfileXPlot", clsGraphTab.enumProfileXPlot.RiverMile)
                            .Reset()
                            '.ResetYAxes()
                            EnableMenus()
                            EnableGraphMenus()
                            With .GraphOptions
                                .GraphTitle = ini.GetKeyText(section, "Title", "")
                                .AutoGraphTitle = ini.GetKeyText(section, "AutoTitle", True)
                                LoadFont(.TitleFont, ini, section, "Title", True)
                                '.GraphBorder = ini.GetKeyText(section, "GraphBorder", False)
                                .UseFontScaleFactor = ini.GetKeyText(section, "UseFontScaleFactor", False) 'when loading legacy graph file, default to false

                                .LegendPos = ini.GetKeyText(section, "LegendPosition", LegendPos.BottomCenter)
                                .LegendVisible = ini.GetKeyText(section, "LegendVisible", True)
                                .LegendBorder = ini.GetKeyText(section, "LegendBorder", True)
                                LoadFont(.LegendFont, ini, section, "Legend", True)

                                .NoteText = ini.GetKeyText(section, "Notes", "")
                                .NoteVisible = ini.GetKeyText(section, "NoteVisible", True)
                                .NotePosition = ini.GetKeyText(section, "NotePosition", enumNotePosition.TopRight)
                                .NoteAlignment = ini.GetKeyText(section, "NoteAlignment", enumNoteAlignment.Center)
                                .NoteBorder = ini.GetKeyText(section, "NoteBorder", True)
                                LoadFont(.NoteFont, ini, section, "Note", True)

                                .FillColor = Color.FromName(ini.GetKeyText(section, "BackgroundColor", System.Drawing.SystemColors.Info.Name))
                                .ZoomOption = ini.GetKeyText(section, "ZoomOption", enumZoomOptions.Auto)
                                .ScrollBars = ini.GetKeyText(section, "ScrollBars", False)
                                .ShowPoints = ini.GetKeyText(section, "ShowPoints", True)
                            End With

                            .ProfileXPlot = ini.GetKeyText(section, "ProfileXPlot", clsGraphTab.enumProfileXPlot.RiverMile)
                            .AnimationInfo.TimeStep = ini.GetKeyText(section, "TimeStep", 60)

                            Dim NumSeries As Integer = ini.GetKeyText(section, "NumSeries", 0)
                            Dim deletedSeries As String = ""

                            'load format for each series; if user didn't save seried formatting, NumSeries was set to 0
                            For i As Integer = 0 To NumSeries - 1
                                section = "Graph" & t & "-Series" & i
                                If ini.GetSectionNames.Contains(section) Then
                                    Dim StationID As String = ini.GetKeyText(section, "StationID", "")
                                    Dim PCode As String = ini.GetKeyText(section, "PCode", "")
                                    Dim DateTime As String = ini.GetKeyText(section, "DateTime", Now)
                                    Dim TimeWindow As enumTimeWindow = ini.GetKeyText(section, "TimeWindow", enumTimeWindow.None)
                                    Dim Units As String = ini.GetKeyText(section, "Units", "")
                                    Dim StationList As String = ini.GetKeyText(section, "StationList", "")
                                    Dim PCodeList As String = ini.GetKeyText(section, "PCodeList", "")
                                    Dim DateList As String = ini.GetKeyText(section, "DateList", "")
                                    Dim IsCalc As Boolean = ini.GetKeyText(section, "IsCalc", "False")
                                    Dim YAxis As clsSeries.enumYAxis = ini.GetKeyText(section, "YAxis", clsSeries.enumYAxis.Left)
                                    Dim YAxisIndex As clsSeries.enumYAxisIndex = ini.GetKeyText(section, "YAxisIndex", clsSeries.enumYAxisIndex.Axis_1)
                                    Dim StatsText As String = ini.GetKeyText(section, "StatsText", "")
                                    Dim StatsPosition As enumNotePosition = ini.GetKeyText(section, "StatsPosition", enumNotePosition.TopRight)
                                    Dim StatsAlignment As enumNoteAlignment = ini.GetKeyText(section, "StatsAlignment", enumNoteAlignment.Center)
                                    Dim StatsVisible As Boolean = ini.GetKeyText(section, "StatsVisible", False)
                                    Dim StatsBorder As Boolean = ini.GetKeyText(section, "StatsBorder", True)
                                    Dim StatsFont As New Font("Tahoma", 8, FontStyle.Regular, GraphicsUnit.Point)
                                    LoadFont(StatsFont, ini, section, "Stats", True)

                                    'load settings that are particular to some graph types
                                    Dim ProfXPlot As String = ini.GetKeyText(section, "ProfXPlot", clsGraphTab.enumProfileXPlot.RiverMile)
                                    Dim ProbOption As String = ini.GetKeyText(section, "ProbOption", enumProbOption.LessThan_Incr)
                                    Dim StationIDX As String = ini.GetKeyText(section, "StationIDX", "")
                                    Dim PCodeX As String = ini.GetKeyText(section, "PCodeX", "")
                                    Dim PCodeListX As String = ini.GetKeyText(section, "PCodeListX", "")

                                    If IsCalc Then
                                        Select Case .GraphType
                                            Case enumGraphType.TimeSeries
                                                .Series.Add(New clsSeriesTimeSeries(.Zed))
                                            Case enumGraphType.Profile
                                                .Series.Add(New clsSeriesLongProfile(.Zed))
                                            Case enumGraphType.Depth
                                                .Series.Add(New clsSeriesDepthProfile(.Zed))
                                            Case enumGraphType.Width
                                                .Series.Add(New clsSeriesWidthProfile(.Zed))
                                            Case enumGraphType.Scatter
                                                .Series.Add(New clsSeriesScatter(.Zed))
                                            Case enumGraphType.Probability
                                                .Series.Add(New clsSeriesProbability(.Zed))
                                            Case enumGraphType.Histogram
                                                .Series.Add(New clsSeriesHistogram(.Zed))
                                            Case enumGraphType.FlowDuration
                                                .Series.Add(New clsSeriesFlowDuration(.Zed))
                                        End Select

                                        If .Series.Count = 0 Then Continue For

                                        Dim ser As clsSeries = .Series(.Series.Count - 1)

                                        With ser
                                            .StationID = StationID
                                            .PCode = PCode
                                            .DateTime = DateTime
                                            .TimeWindow = TimeWindow
                                            .StationList = StationList
                                            .PCodeList = PCodeList
                                            .DateList = DateList
                                            .YAxis = YAxis
                                            .YAxisIndex = YAxisIndex
                                            .StatsAlignment = StatsAlignment
                                            .StatsBorder = StatsBorder
                                            .StatsFont = .StatsFont
                                            .StatsPosition = StatsPosition
                                            .StatsText = StatsText
                                            .StatsVisible = StatsVisible
                                            .IsCalc = IsCalc
                                            Dim sX() As String = ini.GetKeyText(section, "CalcPointsX").Split(",")
                                            Dim sY() As String = ini.GetKeyText(section, "CalcPointsY").Split(",")
                                            For p As Integer = 0 To sX.Length - 1
                                                .ZedCurve.AddPoint(sX(p), sY(p))
                                            Next
                                            .Label = ini.GetKeyText(section, "Label", .Label)
                                            .XAxis = ini.GetKeyText(section, "XAxis", clsSeries.enumXAxis.Bottom)
                                            '.YAxisIndex = ini.GetKeyText(section, "YAxisIndex", 0)
                                            .SmoothCurve = ini.GetKeyText(section, "SmoothCurve", False)
                                            .LineColor = Color.FromName(ini.GetKeyText(section, "LineColor", .LineColor.Name))
                                            .LineType = ini.GetKeyText(section, "LineType", clsSeries.enumLineType.Solid)
                                            .LineWidth = ini.GetKeyText(section, "LineWidth", 1)
                                            .SymbolFill = ini.GetKeyText(section, "SymbolFill", False)
                                            .SymbolType = ini.GetKeyText(section, "SymbolType", .SymbolType)
                                            .SymbolBorderColor = Color.FromName(ini.GetKeyText(section, "SymbolBorderColor", .SymbolBorderColor.Name))
                                            .SymbolFillColor = Color.FromName(ini.GetKeyText(section, "SymbolFillColor", .SymbolFillColor.Name))
                                            .SymbolSize = ini.GetKeyText(section, "SymbolSize", 6)
                                            .Visible = ini.GetKeyText(section, "Visible", "True")
                                        End With
                                    Else
                                        Dim ProjectName As String = ini.GetKeyText(section, "ProjectName", "")
                                        Dim TableName As String = ini.GetKeyText(section, "TableName")
                                        Dim RenamedKey As String = ProjectName & vbTab & TableName
                                        If TableProjectNameMissing Or ProjectName = "" Then 'for backwards compatibility
                                            RenamedKey = TableName
                                        Else
                                            RenamedKey = ProjectName & vbTab & TableName
                                        End If

                                        'in case a data file wasn't found, it was reselected, and the resulting project and/or table name changed
                                        If RenamedProjects.ContainsKey(RenamedKey) Then
                                            ProjectName = RenamedProjects(RenamedKey).Split(vbTab)(0)
                                            TableName = RenamedProjects(RenamedKey).Split(vbTab)(1)
                                        End If

                                        For Each tbl As clsTable In OpenTables
                                            If tbl.ProjectName = ProjectName And
                                                (RemoveBrackets(tbl.TableName.Replace("#", ".")) = RemoveBrackets(TableName.Replace("#", ".")) Or
                                                 tbl.TableName.ToUpper.Replace("#TXT", "") = TableName.ToUpper) Then
                                                If .AddSeries(tbl, StationID, PCode, DateTime, TimeWindow, StationList, PCodeList, DateList, YAxis, YAxisIndex, False) Then

                                                    Dim ser As clsSeries = .Series(.Series.Count - 1)

                                                    With ser
                                                        .Label = ini.GetKeyText(section, "Label", .Label)
                                                        .XAxis = ini.GetKeyText(section, "XAxis", clsSeries.enumXAxis.Bottom)
                                                        '.YAxisIndex = ini.GetKeyText(section, "YAxisIndex", 0)
                                                        .SmoothCurve = ini.GetKeyText(section, "SmoothCurve", False)
                                                        .LineColor = Color.FromName(ini.GetKeyText(section, "LineColor", .LineColor.Name))
                                                        .LineType = ini.GetKeyText(section, "LineType", clsSeries.enumLineType.Solid)
                                                        .LineWidth = ini.GetKeyText(section, "LineWidth", 1)
                                                        .SymbolFill = ini.GetKeyText(section, "SymbolFill", False)
                                                        .SymbolType = ini.GetKeyText(section, "SymbolType", .SymbolType)
                                                        .SymbolBorderColor = Color.FromName(ini.GetKeyText(section, "SymbolBorderColor", .SymbolBorderColor.Name))
                                                        .SymbolFillColor = Color.FromName(ini.GetKeyText(section, "SymbolFillColor", .SymbolFillColor.Name))
                                                        .SymbolSize = ini.GetKeyText(section, "SymbolSize", 6)
                                                        .Visible = ini.GetKeyText(section, "Visible", "True")
                                                        .StatsAlignment = StatsAlignment
                                                        .StatsBorder = StatsBorder
                                                        .StatsFont = .StatsFont
                                                        .StatsPosition = StatsPosition
                                                        .StatsText = StatsText
                                                        .StatsVisible = StatsVisible
                                                        .IsCalc = IsCalc
                                                        'load settings that are particular to some graph types
                                                        Select Case ActiveGraphTab.GraphType
                                                            Case enumGraphType.Profile
                                                                CType(ser, clsSeriesLongProfile).ProfXPlot = ProfXPlot
                                                                .GetData()
                                                            Case enumGraphType.Probability
                                                                CType(ser, clsSeriesProbability).ProbOption = ProbOption
                                                                .GetData()
                                                            Case enumGraphType.Scatter
                                                                CType(ser, clsSeriesScatter).StationIDX = StationIDX
                                                                CType(ser, clsSeriesScatter).PCodeX = PCodeX
                                                                CType(ser, clsSeriesScatter).PCodeListX = PCodeListX
                                                                .GetData()
                                                        End Select
                                                    End With
                                                    Exit For
                                                Else
                                                    deletedSeries &= String.Format("Table: {0}; Station ID: {1}; PCode: {2}\n", tbl.ToString, StationID, PCode)
                                                End If
                                            End If
                                        Next
                                    End If
                                End If
                            Next i

                            If deletedSeries <> "" Then
                                WarningMsg("Unable to load series because table is missing or has changed, or one or more series reference missing Station IDs or PCodes. The following affected series were removed:\n\n{0}", deletedSeries)
                            End If

                            'zoom extents to reset scrollrange property
                            .ZoomExtents()

                            'now load axis settings
                            For i As Integer = 1 To 2
                                Dim axis As New clsAxis(.Zed, Choose(i, clsAxis.enumAxis.XAxis, clsAxis.enumAxis.X2Axis), 0, ActiveGraphTab.GraphOptions.FontScaleFactor)
                                LoadAxis(axis, ini, String.Format("Graph{0}-XAxis{1}", t, i), FormatOnly, True)
                                For j As Integer = 0 To 4
                                    axis = New clsAxis(.Zed, Choose(i, clsAxis.enumAxis.YAxis, clsAxis.enumAxis.Y2Axis), j, ActiveGraphTab.GraphOptions.FontScaleFactor)
                                    LoadAxis(axis, ini, String.Format("Graph{0}-YAxis{1}_{2}", t, i, j), FormatOnly, True)
                                Next
                            Next

                            'box & whisker require correct graph extents to draw properly
                            If .GraphType = enumGraphType.Profile Then
                                For Each ser As clsSeries In .Series
                                    If ser.SymbolType = clsSeries.enumSymbolType.Box_Whisker Then ser.GetData()
                                Next
                            End If

                            'load graph objects

                            section = "Graph" & t
                            Dim NumGraphObj As Integer = ini.GetKeyText(section, "NumGraphObjects", "0")
                            For i As Integer = 0 To NumGraphObj - 1
                                section = "Graph" & t & "-GraphObj" & i
                                Dim ObjType As String = ini.GetKeyText(section, "Type")
                                Dim x1 As Double = ini.GetKeyText(section, "X1")
                                Dim y1 As Double = ini.GetKeyText(section, "Y1")
                                Dim x2 As Double = ini.GetKeyText(section, "X2")
                                Dim y2 As Double = ini.GetKeyText(section, "Y2")
                                Dim clr As Color = Color.FromName(ini.GetKeyText(section, "Color", "Black"))
                                With .Zed.GraphPane.GraphObjList
                                    Dim graphObj As ZedGraph.GraphObj = Nothing
                                    Select Case ObjType.ToUpper
                                        Case "ARROW" : graphObj = New ZedGraph.ArrowObj(clr, clsGraphTab.DrawArrowSize, x1, y1, x2, y2)
                                        Case "LINE" : graphObj = New ZedGraph.LineObj(clr, x1, y1, x2, y2)
                                        Case "ELLIPSE" : graphObj = New ZedGraph.EllipseObj(x1, y1, x2 - x1, y2 - y1, clr, Color.Transparent)
                                        Case "BOX" : graphObj = New ZedGraph.BoxObj(x1, y1, x2 - x1, y2 - y1, clr, Color.Transparent)
                                        Case "TEXTBOX" : graphObj = New ZedGraph.TextObj(ini.GetKeyText(section, "Text").Replace("\n", vbCrLf), x1, y1, CoordType.ChartFraction, AlignH.Center, AlignV.Center)
                                    End Select
                                    graphObj.Location.CoordinateFrame = CoordType.ChartFraction
                                    .Add(graphObj)
                                End With
                            Next
                            WriteProgress(Me, t, NumGraphs - 1, "Loading graph tab: {0} (click status bar to cancel)...", .Name)
                            Application.DoEvents()
                            'Threading.Thread.Sleep(500)
                            If _IsLoadCancelled Then Exit Try

                            With .AnimationInfo
                                section = "Graph" & t
                                .ToolbarVisible = ini.GetKeyText(section, "AnimToolbar", False)
                                .Speed = ini.GetKeyText(section, "AnimSpeed", 3)
                            End With

                            Dim tw As Integer = -1
                            For i As Integer = 0 To TimeWindow.Length - 1
                                If Math.Abs(TimeWindow(i) - .AnimationInfo.TimeStep) < 0.1 Then tw = i : Exit For
                            Next
                            If tw = -1 Then tw = 60
                            '.SetSeriesTimeWindow(tw)
                            ResetAnimationLimits()
                            EnableMenus()
                            EnableGraphMenus()
                            If NumSeries > 0 Then .ResetYAxes()
                            If .GraphType = enumGraphType.Profile Then .ResetProfileScales()
                            .Zed.AxisChange()
                            .Zed.Refresh()
                        End With
                    End With
                Next t

                TabGraph.SelectedIndex = 0
                If OpenTables.Count > 0 And ActiveGraphTab.Series.Count = 0 Then mnuToolsManage.PerformClick()

                'if any data files/tables could not be found and had to be browsed to, set modified flag so will be prompted to save on exit
                _IsModified = False
                For Each kv As Generic.KeyValuePair(Of String, String) In RenamedProjects
                    If kv.Key <> kv.Value Then
                        _IsModified = True
                        Exit For
                    End If
                Next
            End If
            ini = Nothing

        Catch ex As Exception
            ErrorMsg("An error occurred while trying to read the .Graph file.", ex)
        Finally
            statusMain.Cursor = Cursors.Default
            ResetAnimationLimits()
            If ActiveGraphTab() IsNot Nothing Then SetAnimationTimeStep(ActiveGraphTab.AnimationInfo.TimeStep)
            SetTabTooltip()
            UpdateTabDropdown()
            If Not FormatOnly And ActiveGraphTab() IsNot Nothing Then
                FillSeriesList()
                SetAxisProperties()
                tabProperties.SelectedIndex = 0
            End If
            If Not FormatOnly Then WriteProgress(Me)
            LoadingSettings = False
        End Try
    End Sub

    Friend Sub SaveSettings(ByVal FileName As String, Optional ByVal FormatOnly As Boolean = False, Optional ByVal SeriesFormats As Boolean = False)
        Try
            WriteProgress(Me, "Saving to {0}...", FileName)
            If My.Computer.FileSystem.FileExists(FileName) Then My.Computer.FileSystem.DeleteFile(FileName) 'makes it faster because doesn't need to read old one
            Dim ini As New WRDB.IniFile.clsIniFile(FileName, True)
            Dim section As String

            'save print layouts
            ini.SetKeyText("Layouts", "ActiveLayoutName", ActiveLayoutName)
            ini.SetKeyText("Layouts", "NumLayouts", Layouts.Count)
            Dim l As Integer = 0
            For Each Layout As clsLayout In Layouts.Values
                section = "Layout" & l
                With Layout
                    ini.SetKeyText(section, "Name", .Name)
                    ini.SetKeyText(section, "NumRows", .NumRows)
                    ini.SetKeyText(section, "NumCols", .NumCols)
                    ini.SetKeyText(section, "AutoAssign", .AutoAssign)
                    ini.SetKeyText(section, "Landscape", .Landscape)
                    ini.SetKeyText(section, "Margin_Left", .Margins.Left)
                    ini.SetKeyText(section, "Margin_Right", .Margins.Right)
                    ini.SetKeyText(section, "Margin_Top", .Margins.Top)
                    ini.SetKeyText(section, "Margin_Bottom", .Margins.Bottom)
                    ini.SetKeyText(section, "Margin_RowCol", .RowColMargin)
                    ini.SetKeyText(section, "DrawBorders", .DrawBorders)
                    ini.SetKeyText(section, "NumPages", .PageContents.Count)
                    For p As Integer = 0 To .PageContents.Count - 1
                        For r As Integer = 0 To clsLayout.MaxRows - 1
                            For c As Integer = 0 To clsLayout.MaxCols - 1
                                ini.SetKeyText(section, String.Format("Page{0}_Pane_C{1}R{2}", p, c, r), .PageContents(p).Item(c, r))
                            Next
                        Next
                    Next
                End With
                l += 1
            Next

            If Not FormatOnly Then
                'save tables (universal to all graph tabs)
                ini.SetKeyText("Tables", "NumTables", OpenTables.Count, 0)
                For i As Integer = 0 To OpenTables.Count - 1
                    OpenTables(i).SaveSettings(ini, "Table" & i)
                    WriteProgress(Me, i, OpenTables.Count - 1, "Saving tables...")
                Next i
            End If

            ini.SetKeyText("Graphs", "ApplyToAll", ApplyToAllTabs)
            ini.SetKeyText("Graphs", "NumGraphs", IIf(FormatOnly, 1, TabGraph.TabCount - 1), 0)
            For t As Integer = 0 To IIf(FormatOnly, 0, TabGraph.TabCount - 2)
                With ActiveGraphTab(IIf(FormatOnly, TabGraph.SelectedIndex, t))
                    section = "Graph" & t
                    ini.CommentSection(section)
                    ini.SetKeyText(section, "Name", .Name, "Graph " & t + 1)
                    ini.SetKeyText(section, "GraphType", .GraphType, enumGraphType.TimeSeries)
                    With .GraphOptions
                        ini.SetKeyText(section, "Title", .GraphTitle, "")
                        ini.SetKeyText(section, "AutoTitle", .AutoGraphTitle, True)
                        SaveFont(.TitleFont, ini, section, "Title")
                        'ini.SetKeyText(section, "GraphBorder", .GraphBorder, False)
                        ini.SetKeyText(section, "UseFontScaleFactor", .UseFontScaleFactor)

                        ini.SetKeyText(section, "LegendPosition", .LegendPos, LegendPos.BottomCenter)
                        ini.SetKeyText(section, "LegendVisible", .LegendVisible, True)
                        ini.SetKeyText(section, "LegendBorder", .LegendBorder, True)
                        SaveFont(.LegendFont, ini, section, "Legend")

                        ini.SetKeyText(section, "Notes", .NoteText, "")
                        ini.SetKeyText(section, "NoteVisible", .NoteVisible, True)
                        ini.SetKeyText(section, "NotePosition", .NotePosition, enumNotePosition.TopRight)
                        ini.SetKeyText(section, "NoteAlignment", .NoteAlignment, enumNoteAlignment.Center)
                        ini.SetKeyText(section, "NoteBorder", .NoteBorder, True)
                        SaveFont(.NoteFont, ini, section, "Note")

                        ini.SetKeyText(section, "BackgroundColor", .FillColor.Name, System.Drawing.SystemColors.Info.Name)
                        ini.SetKeyText(section, "ZoomOption", .ZoomOption, enumZoomOptions.Auto)
                        ini.SetKeyText(section, "ScrollBars", .ScrollBars)
                        ini.SetKeyText(section, "ShowPoints", .ShowPoints, True)
                    End With
                    With .AnimationInfo
                        ini.SetKeyText(section, "AnimToolbar", .ToolbarVisible, False)
                        ini.SetKeyText(section, "AnimSpeed", .Speed, 3)
                    End With

                    For i As Integer = 1 To 2
                        Dim axis As New clsAxis(.Zed, Choose(i, clsAxis.enumAxis.XAxis, clsAxis.enumAxis.X2Axis), 0, .GraphOptions.FontScaleFactor)
                        SaveAxis(axis, ini, String.Format("Graph{0}-XAxis{1}", t, i))
                        For j As Integer = 0 To 4
                            axis = New clsAxis(.Zed, Choose(i, clsAxis.enumAxis.YAxis, clsAxis.enumAxis.Y2Axis), j, .GraphOptions.FontScaleFactor)
                            SaveAxis(axis, ini, String.Format("Graph{0}-YAxis{1}_{2}", t, i, j))
                        Next
                    Next

                    section = "Graph" & t
                    ini.SetKeyText(section, "ProfileXPlot", .ProfileXPlot, clsGraphTab.enumProfileXPlot.RiverMile)
                    ini.SetKeyText(section, "TimeStep", .AnimationInfo.TimeStep, 60)

                    If FormatOnly And Not SeriesFormats Then
                        ini.SetKeyText(section, "NumSeries", 0)
                    Else
                        section = "Graph" & t
                        ini.SetKeyText(section, "NumSeries", .Series.Count, 0)

                        'store format for each series
                        For i As Integer = 0 To .Series.Count - 1
                            section = "Graph" & t & "-Series" & i
                            Dim ser As clsSeries = .Series(i)
                            With ser
                                ini.SetKeyText(section, "StationID", .StationID)
                                ini.SetKeyText(section, "PCode", .PCode)
                                ini.SetKeyText(section, "DateTime", .DateTime)
                                ini.SetKeyText(section, "TimeWindow", .TimeWindow)
                                ini.SetKeyText(section, "StationList", .StationList)
                                ini.SetKeyText(section, "PCodeList", .PCodeList)
                                ini.SetKeyText(section, "DateList", .DateList)
                                ini.SetKeyText(section, "IsCalc", .IsCalc)
                                ini.SetKeyText(section, "Visible", .Visible)
                                If .IsCalc Then
                                    Dim sX, sY As New System.Text.StringBuilder
                                    For p As Integer = 0 To .ZedCurve.NPts - 1
                                        sX.Append(IIf(p = 0, "", ",") & Math.Round(.ZedCurve.Points(p).X, 3))
                                        sY.Append(IIf(p = 0, "", ",") & Math.Round(.ZedCurve.Points(p).Y, 3))
                                    Next
                                    ini.SetKeyText(section, "CalcPointsX", sX.ToString)
                                    ini.SetKeyText(section, "CalcPointsY", sY.ToString)
                                Else
                                    ini.SetKeyText(section, "ProjectName", .Table.ProjectName)
                                    ini.SetKeyText(section, "TableName", .Table.TableName)
                                End If
                                ini.SetKeyText(section, "Label", .Label)
                                ini.SetKeyText(section, "XAxis", .XAxis, clsSeries.enumXAxis.Bottom)
                                ini.SetKeyText(section, "YAxis", .YAxis, clsSeries.enumYAxis.Left)
                                ini.SetKeyText(section, "YAxisIndex", .YAxisIndex, clsSeries.enumYAxisIndex.Axis_1)
                                ini.SetKeyText(section, "SmoothCurve", .SmoothCurve, False)
                                ini.SetKeyText(section, "LineColor", .LineColor.Name)
                                ini.SetKeyText(section, "LineType", .LineType, clsSeries.enumLineType.Solid)
                                ini.SetKeyText(section, "LineWidth", .LineWidth, 1)
                                ini.SetKeyText(section, "SymbolType", .SymbolType)
                                ini.SetKeyText(section, "SymbolSize", .SymbolSize, 6)
                                ini.SetKeyText(section, "SymbolBorderColor", .SymbolBorderColor.Name)
                                ini.SetKeyText(section, "SymbolFillColor", .SymbolFillColor.Name)
                                ini.SetKeyText(section, "SymbolFill", .SymbolFill, False)
                                ini.SetKeyText(section, "StatsText", .StatsText)
                                ini.SetKeyText(section, "StatsPosition", .StatsPosition)
                                ini.SetKeyText(section, "StatsAlignment", .StatsAlignment)
                                ini.SetKeyText(section, "StatsVisible", .StatsVisible)
                                ini.SetKeyText(section, "StatsBorder", .StatsBorder)
                                SaveFont(.StatsFont, ini, section, "Stats")

                                'save settings that are particular to some graph types
                                Select Case ActiveGraphTab(t).GraphType
                                    Case enumGraphType.Profile
                                        ini.SetKeyText(section, "ProfXPlot", CType(ser, clsSeriesLongProfile).ProfXPlot)
                                    Case enumGraphType.Probability
                                        ini.SetKeyText(section, "ProbOption", CType(ser, clsSeriesProbability).ProbOption)
                                    Case enumGraphType.Scatter
                                        ini.SetKeyText(section, "StationIDX", CType(ser, clsSeriesScatter).StationIDX)
                                        ini.SetKeyText(section, "PCodeX", CType(ser, clsSeriesScatter).PCodeX)
                                        ini.SetKeyText(section, "PCodeListX", CType(ser, clsSeriesScatter).PCodeListX)
                                End Select

                            End With
                            WriteProgress(Me, i, .Series.Count - 1, "Saving series...")
                        Next

                        section = "Graph" & t
                        Dim NumGraphObj As Integer = 0
                        For i As Integer = 0 To .Zed.GraphPane.GraphObjList.Count - 1
                            section = "Graph" & t & "-GraphObj" & NumGraphObj
                            With .Zed.GraphPane.GraphObjList
                                Dim clr As Color = Color.Black
                                If TypeOf .Item(i) Is ZedGraph.ArrowObj Then
                                    ini.SetKeyText(section, "Type", "Arrow")
                                    clr = CType(.Item(i), ArrowObj).Line.Color
                                ElseIf TypeOf .Item(i) Is ZedGraph.LineObj Then
                                    ini.SetKeyText(section, "Type", "Line")
                                    clr = CType(.Item(i), LineObj).Line.Color
                                ElseIf TypeOf .Item(i) Is ZedGraph.EllipseObj Then
                                    ini.SetKeyText(section, "Type", "Ellipse")
                                    clr = CType(.Item(i), EllipseObj).Border.Color
                                ElseIf TypeOf .Item(i) Is ZedGraph.BoxObj Then
                                    ini.SetKeyText(section, "Type", "Box")
                                    clr = CType(.Item(i), BoxObj).Border.Color
                                ElseIf TypeOf .Item(i) Is ZedGraph.TextObj Then 'we are using this to show summary statistics, so don't allow duplicates
                                    Dim s As String = CType(.Item(i), ZedGraph.TextObj).Text.Replace(vbCrLf, "\n")
                                    If .Item(i).Tag IsNot Nothing Then Continue For 'tag is used to identify graph notes and series stats
                                    ini.SetKeyText(section, "Type", "Textbox")
                                    ini.SetKeyText(section, "Text", s)
                                End If
                                With .Item(i)
                                    ini.SetKeyText(section, "X1", .Location.X1.ToString("0.00"))
                                    ini.SetKeyText(section, "Y1", .Location.Y1.ToString("0.00"))
                                    ini.SetKeyText(section, "X2", .Location.X2.ToString("0.00"))
                                    ini.SetKeyText(section, "Y2", .Location.Y2.ToString("0.00"))
                                    ini.SetKeyText(section, "Color", clr.Name)
                                End With
                                NumGraphObj += 1
                            End With
                        Next
                        section = "Graph" & t
                        ini.SetKeyText(section, "NumGraphObjects", NumGraphObj)
                    End If
                End With
            Next t

            If Not FormatOnly Then _IsModified = False

            ini.Save()
            ini = Nothing
        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            WriteProgress(Me)
        End Try
    End Sub

    Private Sub LoadAxis(ByRef Axis As clsAxis, ByVal ini As WRDB.IniFile.clsIniFile, ByVal Section As String, ByVal FormatOnly As Boolean, Optional LegacyFonts As Boolean = False)
        With Axis

            If Not FormatOnly Then
                .AxisType = ini.GetKeyText(Section, "AxisType", .AxisType)
                .AutoTitle = ini.GetKeyText(Section, "AutoTitle", True)
                .Title = ini.GetKeyText(Section, "Title", "")
                .Min = ini.GetKeyText(Section, "Min", 0)
                .Max = ini.GetKeyText(Section, "Max", 100)
                .AutoScaleMin = ini.GetKeyText(Section, "AutoScaleMin", True)
                .AutoScaleMax = ini.GetKeyText(Section, "AutoScaleMax", True)
                .Visible = ini.GetKeyText(Section, "IsVisible", .Visible)
                .AutoTitle = ini.GetKeyText(Section, "AutoTitle", True)
                .MinLimit = ini.GetKeyText(Section, "MinLimit", "Not Set")
                .MaxLimit = ini.GetKeyText(Section, "MaxLimit", "Not Set")
            End If

            LoadFont(.TitleFont, ini, Section, "Title", LegacyFonts)
            LoadFont(.LabelFont, ini, Section, "Label", LegacyFonts)
            .MagAuto = ini.GetKeyText(Section, "MagAuto", .MagAuto)
            .GridLines = ini.GetKeyText(Section, "GridLines", True)
            .GridLinesMinor = ini.GetKeyText(Section, "GridLinesMinor", True)

        End With
    End Sub

    Private Sub SaveAxis(ByVal Axis As clsAxis, ByVal ini As WRDB.IniFile.clsIniFile, ByVal Section As String)
        With Axis
            ini.SetKeyText(Section, "Title", .Title, "")
            ini.SetKeyText(Section, "AutoTitle", .AutoTitle, True)
            ini.SetKeyText(Section, "AxisType", .AxisType)
            ini.SetKeyText(Section, "IsVisible", .Visible)
            SaveFont(.TitleFont, ini, Section, "Title")
            SaveFont(.LabelFont, ini, Section, "Label")
            ini.SetKeyText(Section, "AutoScaleMin", .AutoScaleMin, True)
            ini.SetKeyText(Section, "AutoScaleMax", .AutoScaleMax, True)
            ini.SetKeyText(Section, "Min", .Min, 0)
            ini.SetKeyText(Section, "Max", .Max, 100)
            ini.SetKeyText(Section, "GridLines", .GridLines, True)
            ini.SetKeyText(Section, "GridLinesMinor", .GridLinesMinor, True)
            ini.SetKeyText(Section, "AutoTitle", .AutoTitle, True)
            ini.SetKeyText(Section, "MinLimit", .MinLimit)
            ini.SetKeyText(Section, "MaxLimit", .MaxLimit)
        End With
    End Sub

    Private Sub LoadFont(ByRef fnt As Font, ByVal ini As WRDB.IniFile.clsIniFile, ByVal Section As String, ByVal KeyPrefix As String, Optional LegacyFonts As Boolean = False)
        Dim FontFamily As String = ini.GetKeyText(Section, KeyPrefix & "FontFamily", IIf(LegacyFonts, "Tahoma", fnt.FontFamily.Name))
        Dim Size As Integer = ini.GetKeyText(Section, KeyPrefix & "FontSize", IIf(LegacyFonts, 10, fnt.Size))
        Dim IsBold As Boolean = ini.GetKeyText(Section, KeyPrefix & "FontIsBold", IIf(LegacyFonts, False, fnt.Bold))
        Dim IsItalic As Boolean = ini.GetKeyText(Section, KeyPrefix & "FontIsItalic", IIf(LegacyFonts, False, fnt.Italic))
        Dim IsUnderline As Boolean = ini.GetKeyText(Section, KeyPrefix & "FontIsUnderline", IIf(LegacyFonts, False, fnt.Underline))
        fnt = New Font(FontFamily, Size, IIf(IsBold, FontStyle.Bold, 0) + IIf(IsItalic, FontStyle.Italic, 0) + IIf(IsUnderline, FontStyle.Underline, 0), GraphicsUnit.Point)
    End Sub

    Private Sub SaveFont(ByVal fnt As Font, ByVal ini As WRDB.IniFile.clsIniFile, ByVal Section As String, ByVal KeyPrefix As String)
        With fnt
            ini.SetKeyText(Section, KeyPrefix & "FontFamily", .FontFamily.Name, "Tahoma")
            ini.SetKeyText(Section, KeyPrefix & "FontSize", .Size, 10)
            ini.SetKeyText(Section, KeyPrefix & "FontIsBold", .Bold, False)
            ini.SetKeyText(Section, KeyPrefix & "FontIsItalic", .Italic, False)
            ini.SetKeyText(Section, KeyPrefix & "FontIsUnderline", .Underline, False)
        End With
    End Sub

#End Region

    ''' <summary>
    ''' Add all data from first open table and create series
    ''' </summary>
    Public Sub AddSeries(ByVal StationID As String, ByVal PCode As String)
        Try
            With ActiveGraphTab(0)
                .AddSeries(OpenTables(0), StationID, PCode, Date.MinValue, enumTimeWindow.All, StationID, PCode, "", clsSeries.enumYAxis.Left, clsSeries.enumYAxisIndex.Axis_1, False)
                .Zed.AxisChange()
                .Zed.Refresh()
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Add new graph tab and make active (if the current graphtab has no series, it will use that one)
    ''' </summary>
    Public Sub AddGraphTab()
        Try
            If ActiveGraphTab() IsNot Nothing AndAlso ActiveGraphTab.Series.Count = 0 Then Exit Sub
            With TabGraph
                .TabPages.Insert(.TabCount - 1, "Graph " & .TabCount - 1)
                AddGraphTab(.TabPages(.TabCount - 2))
                .SelectedIndex = .TabCount - 2
                .TabPages(.TabCount - 2).ImageIndex = 0
                ResetAnimationLimits()
                'ActiveGraphTab.Reset()
                LoadSettings()
                SetTabTooltip()
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub AddGraphTab(ByVal NewTab As TabPage)
        Try
            Dim DefaultFile As String = My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData & "\Default.graph"
            Dim Zed As New ZedGraph.ZedGraphControl
            Zed.Dock = DockStyle.Fill
            HelpProvider1.SetHelpString(Zed, "Add series to this graph and control their formats using Tools | Manage Series or the Series toolbar button. General properties are set by clicking Tools | Options or clicking the Options toolbar button. Use the left mouse button or wheel to zoom; hold the wheel button to pan. Right-click for more options. See the online help for more information on this control.")
            HelpProvider1.SetShowHelp(Zed, True)
            'ToolTip.SetToolTip(Zed, "Press F1 for help")
            With NewTab
                TabGraph.SelectedIndex = TabGraph.TabCount - 2
                .ImageIndex = 0
                .Controls.Add(Zed)
                .Tag = New clsGraphTab(Zed)
                .Text = "Graph " & TabGraph.TabCount - 1
                ActiveGraphTab.Name = .Text
                'Roy says these take too much space
                '.ToolTipText = .Text
                If Not LoadingSettings Then GraphForm.LoadSettings()
            End With

        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Function GetTabPageByTab(ByVal pt As Point) As TabPage
        With TabGraph
            For i As Integer = 0 To .TabCount - 1
                If .GetTabRect(i).Contains(pt) Then Return .TabPages(i)
            Next
            Return Nothing
        End With
    End Function

    Private Sub TabGraph_ControlRemoved(sender As Object, e As System.Windows.Forms.ControlEventArgs) Handles TabGraph.ControlRemoved
        UpdateTabDropdown()
    End Sub

    ''' <summary>
    ''' New tabpage has been added to tab control; add ZedGraph control to page and instantiate new TabGraph object to hold all settings
    ''' </summary>
    Private Sub TabGraph_ControlAdded(ByVal sender As Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles TabGraph.ControlAdded
        'make active graph tab colorful, rest are gray
        With TabGraph
            For i As Integer = 0 To .TabCount - 2
                .TabPages(i).ImageIndex = IIf(i = .SelectedIndex, 0, 2)
            Next
        End With
        UpdateTabDropdown()
    End Sub

    Private Sub UpdateTabDropdown()
        tbTabs.DropDownItems.Clear()
        With TabGraph
            For i As Integer = 0 To .TabCount - 1
                tbTabs.DropDownItems.Add(.TabPages(i).Text)
            Next
        End With
    End Sub

    Private Sub tbTabs_DropDownItemClicked(sender As Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles tbTabs.DropDownItemClicked
        With TabGraph
            If e.ClickedItem.Text = "New..." Then
                If LoadingSettings Then
                    .TabPages.Insert(.TabCount - 1, "")
                    AddGraphTab(.TabPages(.TabCount - 2))
                Else
                    If Not PromptNewTab() Then .SelectedIndex = .TabCount - 2
                End If
            Else
                .SelectedIndex = tbTabs.DropDownItems.IndexOf(e.ClickedItem)
            End If
        End With
    End Sub

    Private Sub TabGraph_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TabGraph.DragOver
        Try
            Dim pt As Point = New Point(e.X, e.Y)
            pt = TabGraph.PointToClient(pt)

            Dim hover_tab As TabPage = GetTabPageByTab(pt)

            If Not hover_tab Is Nothing Then 'Make sure we are on a tab. 

                If e.Data.GetDataPresent(GetType(TabPage)) Then 'Make sure there is a TabPage being dragged. 
                    e.Effect = DragDropEffects.Move
                    Dim drag_tab As TabPage = CType(e.Data.GetData(GetType(TabPage)), TabPage)
                    Dim item_drag_index As Integer = TabGraph.TabPages.IndexOf(drag_tab)
                    Dim drop_location_index As Integer = TabGraph.TabPages.IndexOf(hover_tab)


                    'Don't do anything if we are hovering over ourself or over the last New... tab 
                    If item_drag_index <> drop_location_index And drop_location_index <> TabGraph.TabCount - 1 Then
                        Dim pages As ArrayList = New ArrayList()

                        'Put all tab pages into an array, except the one we are dragging. 
                        For i As Integer = 0 To TabGraph.TabPages.Count - 1
                            If i <> item_drag_index Then pages.Add(TabGraph.TabPages(i))
                        Next

                        'Now put the one we are dragging it at the proper location. 
                        pages.Insert(drop_location_index, drag_tab)

                        'Make them all go away for a nanosec. 
                        TabGraph.TabPages.Clear()

                        'Add them all back in. 
                        TabGraph.TabPages.AddRange(pages.ToArray(GetType(TabPage)))

                        'Make sure the drag tab is selected. 
                        TabGraph.SelectedTab = drag_tab
                    End If
                End If
            Else
                e.Effect = DragDropEffects.None
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub TabGraph_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TabGraph.MouseDown
        Try
            If e.Button = Windows.Forms.MouseButtons.Left Then
                If e.Clicks = 1 Then
                    With TabGraph
                        Dim tp As TabPage = GetTabPageByTab(e.Location)
                        If tp IsNot Nothing Then
                            If tp.Text = "New..." Then
                                If LoadingSettings Then
                                    .TabPages.Insert(.TabCount - 1, "")
                                    AddGraphTab(.TabPages(.TabCount - 2))
                                Else
                                    If Not PromptNewTab() Then TabGraph.SelectedIndex = TabGraph.TabCount - 2
                                End If
                            Else
                                DoDragDrop(tp, DragDropEffects.All)
                            End If
                        End If
                    End With
                Else
                    mnuTabGraphRename.PerformClick()
                End If
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub TabGraph_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TabGraph.MouseUp
        Try
            Dim tp As TabPage = GetTabPageByTab(e.Location)
            With TabGraph
                If e.Button = Windows.Forms.MouseButtons.Right Then 'select tab and then show context menu (unless New tab)
                    If tp IsNot Nothing AndAlso tp.Text <> "New..." Then
                        .SelectTab(tp)
                        mnuTabGraph.Show(TabGraph, e.Location)
                    End If
                ElseIf e.Button = Windows.Forms.MouseButtons.Left Then
                    'If tp IsNot Nothing AndAlso tp.Text = "New..." Then
                    '    If LoadingSettings Then
                    '        .TabPages.Insert(.TabCount - 1, "")
                    '        AddGraphTab(.TabPages(.TabCount - 2))
                    '    Else
                    '        If Not PromptNewTab() Then TabGraph.SelectedIndex = TabGraph.TabCount - 2
                    '    End If
                    'End If
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub TabGraph_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TabGraph.SelectedIndexChanged
        Try
            With TabGraph
                If .SelectedTab Is Nothing Then Exit Sub
                AnimTimer.Enabled = False
                ResetAnimationLimits()
                If .SelectedTab.Text = "New..." Then
                    If .TabCount >= 2 Then
                        .SelectedIndex = .TabCount - 2 'don't allow selection of New tab
                    End If
                    Exit Sub
                Else
                    If .SelectedTab.Tag Is Nothing Then Exit Sub
                    'make active graph tab colorful, rest are gray
                    For i As Integer = 0 To .TabCount - 2
                        .TabPages(i).ImageIndex = IIf(i = .SelectedIndex, 0, 2)
                    Next
                End If
            End With
            EnableMenus()
            EnableGraphMenus()
            If TableForm IsNot Nothing Then TableForm.Refresh()
            If StatsForm IsNot Nothing Then StatsForm.Refresh()
            FillSeriesList()
            SetAxisProperties()
            TabGraph.Select()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Friend Sub FillSeriesList()
        Try
            With lstSeries.Items
                .Clear()
                For i As Integer = 0 To ActiveGraphTab.Series.Count - 1
                    Dim ser As clsSeries = ActiveGraphTab.Series(i)
                    If ser.Table IsNot Nothing AndAlso ser.Table.TableType = clsTable.enumTableType.Calibration Then
                        .Add(ser.Table.Calibration.Name)
                    Else
                        .Add(ser.Label)
                    End If
                    lstSeries.SetItemChecked(i, ser.Visible)
                Next
            End With
            If lstSeries.Items.Count > 0 Then lstSeries.SelectedIndex = 0
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Function PromptNewTab() As Boolean
        Try
            'if adding additional graph tab, prompt for type and series (unless adding programmatically)
            With New frmGraphType
                .txtName.Text = "Graph " & TabGraph.TabCount
                .txtName.SelectAll()
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    TabGraph.TabPages.Insert(TabGraph.TabCount - 1, .txtName.Text)
                    AddGraphTab(TabGraph.TabPages(TabGraph.TabCount - 2))
                    ActiveGraphTab.GraphType = .GraphType
                    ChangeGraphType(.GraphType)
                    ActiveGraphTab.Name = .txtName.Text
                    TabGraph.TabPages(TabGraph.TabCount - 2).Text = .txtName.Text
                    'ActiveGraphTab.Reset()
                    trkAnim.Value = 0
                    With New frmSeries
                        .ShowDialog(Me)
                        ResetAnimationLimits()
                        SetTabTooltip()
                        If TableForm IsNot Nothing Then TableForm.Refresh()
                        If StatsForm IsNot Nothing Then StatsForm.Refresh()
                        .Dispose()
                    End With
                    _IsModified = True
                    SetAxisProperties()
                    FillSeriesList()
                    If .GraphType = enumGraphType.Profile Then tbAnim.Visible = True
                    UpdateTabDropdown()
                    Return True
                Else
                    .Dispose()
                    Return False
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
            Return False
        End Try
    End Function

    Private Sub tbAnim_ItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles tbAnim.ItemClicked
        Try
            If Not CheckAnimationBMDSeries() Then Exit Sub

            With trkAnim
                If e.ClickedItem Is tbAnimBeg Then
                    tbAnimPause.PerformClick()
                    .Value = .Minimum
                    ActiveGraphTab.Zed.AxisChange()
                ElseIf e.ClickedItem Is tbAnimEnd Then
                    tbAnimPause.PerformClick()
                    .Value = .Maximum
                    ActiveGraphTab.Zed.AxisChange()
                ElseIf e.ClickedItem Is tbAnimNext Then
                    tbAnimPause.PerformClick()
                    If .Value + .SmallChange > .Maximum Then
                        .Value = .Minimum
                    Else
                        .Value += .SmallChange
                    End If
                ElseIf e.ClickedItem Is tbAnimPrev Then
                    tbAnimPause.PerformClick()
                    If .Value - .SmallChange < .Minimum Then
                        .Value = .Maximum
                    Else
                        .Value -= .SmallChange
                    End If
                ElseIf e.ClickedItem Is tbAnimPause Then
                    AnimTimer.Enabled = False
                    tbAnimPlay.Checked = False
                    mnuViewAnimate.Checked = False
                ElseIf e.ClickedItem Is tbAnimPlay Then
                    AnimTimer.Enabled = Not tbAnimPlay.Checked
                    mnuViewAnimate.Checked = tbAnimPlay.Checked
                ElseIf e.ClickedItem Is tbAnimAvi Then
                    mnuFileMovie.PerformClick()
                ElseIf e.ClickedItem Is tbAnimClose Then
                    tbAnimPause.PerformClick()
                    tbAnim.Visible = False
                End If
            End With
            ToolTip.Active = Not AnimTimer.Enabled
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub tbAnim_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles tbAnim.Paint
        With trkAnim
            '.Left = tbAnim.Left + tbAnimBeg.Width * 0.2
            '.Top = tbAnim.Top + tbAnim.Height * 0.1
            '.Height = tbAnim.Height * 0.8
            '.Width = tbAnim.Width - tbAnimBeg.Width * 10
            .BringToFront()
        End With
    End Sub

    Private Sub tbAnim_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles tbAnim.VisibleChanged
        If ActiveGraphTab() IsNot Nothing Then ActiveGraphTab.AnimationInfo.ToolbarVisible = tbAnim.Visible
        trkAnim.Visible = tbAnim.Visible
        mnuToolbarAnim.Checked = tbAnim.Visible
        mnuTbAnim.Checked = tbAnim.Visible
        'AnimTimer.Enabled = tbAnim.Visible
        'ToolTip.Active = Not AnimTimer.Enabled
    End Sub

    ''' <summary>
    ''' See if only non-BMD series loaded; if so, warn and cancel
    ''' </summary>
    Private Function CheckAnimationBMDSeries() As Boolean
        Try
            Return True

            'this is more trouble than it is worth!!!

            If tbAnim.Visible And ActiveGraphTab() IsNot Nothing Then
                Dim found As Boolean = False
                For Each ser As clsSeries In ActiveGraphTab.Series
                    If Not ser.IsCalc AndAlso ser.Table.TableType = clsTable.enumTableType.BMD Then found = True : Exit For
                Next
                If Not found Then
                    tbAnim.Visible = False
                    trkAnim.Visible = False
                    mnuToolbarAnim.Checked = False
                    mnuTbAnim.Checked = False
                    AnimTimer.Enabled = False
                    'WarningMsg("You cannot animate graphs that have no BMD-type series.")
                End If
                Return found
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try

    End Function

    Private Sub tbAnimSpeed_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuViewAnimateSpeed.DropDownItemClicked, tbAnimSpeed.DropDownItemClicked
        Dim Index As Integer = sender.DropDownItems.IndexOf(e.ClickedItem)
        ActiveGraphTab.AnimationInfo.Speed = Index + 1
        AnimTimer.Interval = 1 + (4 - Index) * 100 'will range from 1 to 401 milliseconds delay
        CheckDropDownItem(mnuViewAnimateSpeed, Index)
        CheckDropDownItem(tbAnimSpeed, Index)
    End Sub

    Private Sub tbMain_ItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles tbMain.ItemClicked

        tbAnimPause.PerformClick()

        Select Case e.ClickedItem.Name

            Case tbNewGroup.Name : mnuFileNew.PerformClick()
            Case tbOpenGroup.Name : mnuFileOpenGroup.PerformClick()
            Case tbSave.Name : mnuFileSaveGroup.PerformClick()
            Case tbSaveAs.Name : mnuFileSaveGroupAs.PerformClick()
            Case tbOpenLast.Name : mnuFileOpenLast.PerformClick()

            Case tbOpen.Name : If GetSetting(REGAPP, "General", "LastOpenType", "File") = "File" Then mnuFileOpen.PerformClick() Else mnuFileOpenTable.PerformClick()
            Case tbClose.Name : mnuFileClose.PerformClick()
            Case tbReplace.Name : mnuFileReplace.PerformClick()
            Case tbExtData.Name : mnuFileOpenExternal.PerformClick()
            Case tbCalib.Name : mnuFileCalibration.PerformClick()

            Case tbCopy.Name : mnuViewCopy.PerformClick()
            Case tbRefresh.Name : mnuViewRefresh.PerformClick()
            Case tbImage.Name : mnuFileImage.PerformClick()
            Case tbPrint.Name : mnuFilePrint.PerformClick()
            Case tbExcel.Name : mnuFileExcel.PerformClick()
            Case tbMovie.Name : mnuFileMovie.PerformClick()
            Case tbArchive.Name : mnuFileArchive.PerformClick()
            Case tbPageSetup.Name : mnuFilePrintSetup.PerformClick()
            Case tbPrint.Name : mnuFilePrint.PerformClick()

            Case tbZoomPrev.Name : mnuViewZoomPrev.PerformClick()
            Case tbZoomLimits.Name : mnuViewZoomLimits.PerformClick()
            Case tbZoomAll.Name : mnuViewZoomAll.PerformClick()

            Case tbSeries.Name : mnuToolsManage.PerformClick()
            Case tbOptions.Name : mnuToolsOptions.PerformClick()

            Case tbGridlines.Name : mnuViewGridlines.PerformClick()
            Case tbLegend.Name : mnuViewLegend.PerformClick()
            Case tbTable.Name : mnuViewData.PerformClick()
            Case tbStats.Name : mnuViewStats.PerformClick()
            Case tbGIS.Name : mnuToolsGIS.PerformClick()

            Case tbDateTime.Name : mnuGraphDateTime.PerformClick()

            Case tbIntervals.Name : mnuGraphIntervals.PerformClick()

            Case tbWhatsThis.Name : mnuHelpWhatsThis.PerformClick()
            Case tbHelp.Name : mnuHelpContents.PerformClick()
        End Select
    End Sub

    Private Sub trkAnim_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles trkAnim.MouseDown
        AnimTimer.Enabled = False
    End Sub

    Private Sub trkAnim_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles trkAnim.ValueChanged
        Try
            With ActiveGraphTab()
                If .GraphType = enumGraphType.TimeSeries Then
                    Dim NodeNum As Integer = CInt(trkAnim.Value * 1.0 / (trkAnim.Maximum - trkAnim.Minimum) * .AnimationInfo.MaxNode)
                    .SetSeriesNode(NodeNum)
                    For Each ser As clsSeries In .Series
                        If ser.Visible Then
                            'If ser.Table.TableType = clsTable.enumTableType.BMD Then
                            'ToolTip.ToolTipTitle = "Current Station ID:"
                            ToolTip.SetToolTip(trkAnim, ser.StationID)
                            'If .GraphOptions.AutoGraphTitle Then .GraphOptions.GraphTitle = String.Format("Station ID: {0}", ser.StationID)
                            Exit For
                        End If
                    Next
                    .AnimationInfo.NodeNum = NodeNum
                Else
                    With .AnimationInfo
                        Dim NumSteps As Integer = CInt(trkAnim.Value / (trkAnim.Maximum - trkAnim.Minimum) * .MaxDate.Subtract(.MinDate).TotalMinutes / .TimeStep)
                        .DateTime = .MinDate.AddMinutes(NumSteps * .TimeStep)
                        ActiveGraphTab.SetSeriesDateTime(.DateTime)
                        ToolTip.SetToolTip(trkAnim, .DateTime.ToString(MyDateTimeFormat))
                    End With
                End If
                ToolTip.Active = Not AnimTimer.Enabled
                ActiveGraphTab.SetGraphTitle()
                ActiveGraphTab.Zed.Refresh()
            End With
        Catch ex As Exception
            AnimTimer.Stop()
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuTabGraph_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuTabGraphAdd.Click, mnuTabGraphRemove.Click, mnuTabGraphRemoveAllButThis.Click, mnuTabGraphRename.Click, mnuTabGraphCopy.Click, mnuTabGraphApplyAll.Click, mnuTabAdd.Click, mnuTabRemove.Click, mnuTabRemoveAllButThis.Click, mnuTabRename.Click, mnuTabCopy.Click, mnuTabApplyAll.Click, mnuTabGraphRemoveAll.Click, mnuTabRemoveAll.Click
        Try
            With TabGraph
                If sender Is mnuTabGraphAdd Or sender Is mnuTabAdd Then
                    'simulate clicking of add graph tab (add to end)
                    If Not PromptNewTab() Then TabGraph.SelectedIndex = TabGraph.TabCount - 2

                ElseIf sender Is mnuTabGraphCopy Or sender Is mnuTabCopy Then
                    Dim sel As Integer = .SelectedIndex + 1
                    .TabPages.Insert(sel, "Copy of " & .SelectedTab.Text)
                    With .TabPages(sel)
                        Dim Tab As clsGraphTab = clsGraphTab.Clone(ActiveGraphTab(TabGraph.SelectedIndex))
                        Tab.Zed.Dock = DockStyle.Fill
                        .Tag = Tab
                        .Controls.Add(Tab.Zed)
                        Tab.Zed.AxisChange()
                        Tab.Zed.Refresh()
                        '.ToolTipText = .Text
                        .ImageIndex = 0
                    End With
                    .SelectedIndex = sel
                    ActiveGraphTab.Name = .SelectedTab.Text
                    _IsModified = True

                ElseIf sender Is mnuTabGraphRemove Or sender Is mnuTabRemove Then
                    If ExpertMode OrElse WarningMsg("Are you sure you want to permanently remove the graph tab named " & .SelectedTab.Text & "?") = Windows.Forms.DialogResult.OK Then
                        .TabPages.Remove(.SelectedTab)
                        _IsModified = True
                    End If

                ElseIf sender Is mnuTabGraphRemoveAllButThis Or sender Is mnuTabRemoveAllButThis Then
                    If ExpertMode OrElse WarningMsg("Are you sure you want to permanently remove all graph tabs except the current one named " & .SelectedTab.Text & "?") = Windows.Forms.DialogResult.OK Then
                        Dim sel As Integer = .SelectedIndex
                        For i As Integer = .TabCount - 2 To 0 Step -1
                            If i <> sel Then .TabPages.RemoveAt(i)
                        Next
                        .SelectedIndex = 0
                        _IsModified = True
                    End If

                ElseIf sender Is mnuTabGraphRemoveAll Or sender Is mnuTabRemoveAll Then
                    If ExpertMode OrElse WarningMsg("Are you sure you want to permanently remove all graph tabs?") = Windows.Forms.DialogResult.OK Then
                        Dim sel As Integer = .SelectedIndex
                        For i As Integer = .TabCount - 2 To 0 Step -1
                            .TabPages.RemoveAt(i)
                        Next
                        .TabPages.Insert(0, "")
                        AddGraphTab(.TabPages(0))
                        .SelectedIndex = 0
                        _IsModified = True
                    End If

                ElseIf sender Is mnuTabGraphRename Or sender Is mnuTabRename Then
                    Dim s As String = InputBox("Enter the new name for this tab:", "Rename Tab", .TabPages(.SelectedIndex).Text)
                    If s <> "" Then
                        .TabPages(.SelectedIndex).Text = s
                        ActiveGraphTab.Name = s
                        _IsModified = True
                    End If

                ElseIf sender Is mnuTabGraphApplyAll Or sender Is mnuTabApplyAll Then
                    ApplyToAllTabs = sender.Checked
                    mnuTabGraphApplyAll.Checked = ApplyToAllTabs
                    mnuTabApplyAll.Checked = ApplyToAllTabs
                End If

                EnableMenus()
                EnableGraphMenus()
                If TableForm IsNot Nothing Then TableForm.Refresh()
                If StatsForm IsNot Nothing Then StatsForm.Refresh()
                .Select()
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuTabGraphMove_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuTabGraphMove.DropDownItemClicked, mnuTabMove.DropDownItemClicked
        Try
            With TabGraph
                Dim sel As Integer = .SelectedIndex
                Dim selectedTab As TabPage = .SelectedTab
                Dim index As Integer
                If sender Is mnuTabGraphMove Then
                    index = mnuTabGraphMove.DropDownItems.IndexOf(e.ClickedItem)
                Else
                    index = mnuTabMove.DropDownItems.IndexOf(e.ClickedItem)
                End If

                Select Case index
                    Case 0 'beginning
                        If sel > 0 Then
                            .TabPages.Insert(0, selectedTab.Text)
                            With .TabPages(0)
                                .ImageIndex = 0
                                .Controls.Add(selectedTab.Controls(0))
                                .Tag = selectedTab.Tag
                            End With
                            .TabPages.Remove(selectedTab)
                            .SelectedIndex = 0
                        End If
                    Case 1 'previous
                        If sel > 0 Then
                            .TabPages.Insert(sel - 1, selectedTab.Text)
                            With .TabPages(sel - 1)
                                .ImageIndex = 0
                                .Controls.Add(selectedTab.Controls(0))
                                .Tag = selectedTab.Tag
                            End With
                            .TabPages.Remove(selectedTab)
                            .SelectedIndex = sel - 1
                        End If
                    Case 2 'next
                        If sel < .TabPages.Count - 2 Then
                            .TabPages.Insert(sel + 2, selectedTab.Text)
                            With .TabPages(sel + 2)
                                .ImageIndex = 0
                                .Controls.Add(selectedTab.Controls(0))
                                .Tag = selectedTab.Tag
                            End With
                            .TabPages.Remove(selectedTab)
                            .SelectedIndex = sel + 1
                        End If
                    Case 3 'last
                        If sel < .TabPages.Count - 2 Then
                            .TabPages.Insert(.TabPages.Count - 1, selectedTab.Text)
                            With .TabPages(.TabPages.Count - 2)
                                .ImageIndex = 0
                                .Controls.Add(selectedTab.Controls(0))
                                .Tag = selectedTab.Tag
                            End With
                            .TabPages.Remove(selectedTab)
                            .SelectedIndex = .TabPages.Count - 2
                        End If
                End Select
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuHelp_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuHelpAbout.Click, mnuHelpContents.Click, mnuHelpEMail.Click, mnuHelpWeb.Click, mnuHelpWhatsThis.Click, mnuHelpUpdates.Click
        Try
            Select Case mnuHelp.DropDownItems.IndexOf(sender)
                Case 0 : ShowHelp()
                Case 1 : VB6.WhatsThisMode(Me)
                Case 3 : Process.Start("http://www.wrdb.com")
                Case 4 : Process.Start("mailto:cwilson@wileng.com")
                Case 6 : UpdatesInstalled(True)
                Case 7
                    With New frmAbout
                        .ShowDialog(Me)
                        .Dispose()
                    End With
                    'VB6.ShowForm(frmAbout, VB6.FormShowConstants.Modal, Me)
                Case Else
                    WarningMsg("This is not yet implemented.")
            End Select
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFileImage_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileImage.Click
        Try
            Static AlreadyWarned As Boolean = False
            Dim MinTab, MaxTab As Integer
            Dim ApplyToAll As Boolean, Resize As Boolean, Resolution As Integer, ImageFormat As frmImage.enumFormat, ImageWidth As Double, ImageHeight As Double, filename As String = "", PrintLayoutName As String = ""

            With New frmImage
                .cboLayout.Text = ActiveLayoutName

                If .ShowDialog(GraphForm) = Windows.Forms.DialogResult.OK Then
                    Resize = .chkResize.Checked
                    Resolution = Val(.txtResolution.Text)
                    ImageFormat = .cboFormat.SelectedIndex
                    SaveSetting(REGAPP, "SendToImage", "Resize", Resize)
                    SaveSetting(REGAPP, "SendToImage", "Resolution", Resolution)
                    SaveSetting(REGAPP, "SendToImage", "Format", ImageFormat)
                    ImageWidth = Val(.txtWidth.Text)
                    ImageHeight = Val(.txtHeight.Text)
                    PrintLayoutName = .cboLayout.Text
                    ApplyToAll = .chkAllGraphs.Checked
                    .Dispose()
                Else
                    .Dispose()
                    Exit Sub
                End If
            End With

            Dim Layout As clsLayout = Nothing
            If PrintLayoutName.StartsWith("(Single") Then
                Layout = New clsLayout("Temp")
                With Layout
                    .NumRows = 1
                    .NumCols = 1
                    .AutoAssign = True
                End With
            Else
                If Not Layouts.TryGetValue(PrintLayoutName, Layout) Then Exit Sub
                ActiveLayoutName = PrintLayoutName
            End If

            If ApplyToAll And Layout.AutoAssign Then
                MinTab = 0 : MaxTab = GraphForm.TabGraph.TabPages.Count - 2
            Else
                MinTab = GraphForm.TabGraph.SelectedIndex : MaxTab = MinTab + Layout.PageContents.Count - 1
            End If

            'loop through all (or just this) tabs

            Dim CurrentTab As Integer = MinTab

            While CurrentTab <= MaxTab

                If Resize Then 'use page setup arrangement

                    Dim PageImage As New Bitmap(CInt(ImageWidth * Resolution), CInt(ImageHeight * Resolution))
                    PageImage.SetResolution(Resolution, Resolution)
                    With Graphics.FromImage(PageImage)
                        .FillRectangle(New SolidBrush(Color.White), New Rectangle(0, 0, PageImage.Width, PageImage.Height))
                    End With

                    If ApplyToAll And Layout.NumCols = 1 And Layout.NumRows = 1 Then
                        filename = GraphForm.TabGraph.TabPages(CurrentTab).Text 'default to name of first tab on page
                    Else
                        filename = String.Format("{0}-{1} of {2}", Layout.Name, (CurrentTab - MinTab) / (Layout.NumRows * Layout.NumCols) + 1, Int((MaxTab - MinTab + 1) / (Layout.NumRows * Layout.NumCols) + 0.99))
                    End If

                    For r As Integer = 0 To Layout.NumRows - 1
                        For c As Integer = 0 To Layout.NumCols - 1

                            'following are in inches
                            Dim BaseDimension As Double = ImageWidth
                            Dim Width As Double = (ImageWidth - Layout.RowColMargin * (Layout.NumCols - 1)) / Layout.NumCols
                            Dim Height As Double = (ImageHeight - Layout.RowColMargin * (Layout.NumRows - 1)) / Layout.NumRows
                            Dim XOffset As Double = c * Width + Layout.RowColMargin * c
                            Dim YOffset As Double = r * Height + Layout.RowColMargin * r

                            If Layout.AutoAssign Then
                                RenderGraphPane(ActiveGraphTab(CurrentTab), ImageWidth, Width, Height, XOffset, YOffset, Resolution, Graphics.FromImage(PageImage))
                                CurrentTab += 1
                                If CurrentTab > MaxTab Then Exit For
                            Else 'will render only single image with specified graph tabs
                                Dim CalibrationName As String = "", Branch As String = "", Station As String = "", Parameter As String = ""
                                If Layout.PageContents(CurrentTab).Item(c, r) = "None" Then
                                    'don't do anything
                                ElseIf clsCalibration.TryParseCalibrationString(Layout.PageContents(CurrentTab).Item(c, r), CalibrationName, Branch, Station, Parameter) Then 'is calibration statistics report
                                    Dim Html As String = CalibrationTable(CalibrationName).Calibration.CreateReport(Station, Parameter, HTMLBuilder.clsHTMLBuilder.enumFontSize.Huge)
                                    RenderGraphPane(Html, BaseDimension, Width, Height, XOffset, YOffset, Resolution, Graphics.FromImage(PageImage))
                                Else
                                    For t As Integer = 0 To TabGraph.TabCount - 1
                                        If TabGraph.TabPages(t).Text = Layout.PageContents(CurrentTab).Item(c, r) Then
                                            RenderGraphPane(ActiveGraphTab(t), BaseDimension, Width, Height, XOffset, YOffset, Resolution, Graphics.FromImage(PageImage))
                                            Exit For
                                        End If
                                    Next
                                End If
                            End If
                        Next
                        If CurrentTab > MaxTab Then Exit For
                    Next

                    If Not (ApplyToAll And Layout.AutoAssign) Then CurrentTab += 1

                    'send currently rendered image to clipboard or file

                    If ImageFormat = frmImage.enumFormat.Metafile Then
                        ClipboardMetafileHelper.CopyToClip(PageImage)
                    ElseIf ImageFormat = frmImage.enumFormat.Bitmap Then
                        Clipboard.SetImage(PageImage)
                    Else
                        Dim fmt As Imaging.ImageFormat = Imaging.ImageFormat.Jpeg

                        filename = GetSetting(REGAPP, "SendToImage", "Directory", AppDataPath) & "\" & filename & ".jpg"

                        If ExpertMode And CurrentTab <> MinTab Then
                            PageImage.Save(filename, fmt)
                        Else
                            With New SaveFileDialog
                                .AddExtension = True
                                .InitialDirectory = GetSetting(REGAPP, "SendToImage", "Directory", AppDataPath)
                                .FileName = filename
                                .Filter = "JPEG|*.jpg|BMP|*.bmp|GIF|*.gif|PNG|*.png|TIFF|*.tif"
                                .FileName = filename
                                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                                    Dim ext As String = IO.Path.GetExtension(.FileName).ToUpper
                                    Select Case ext
                                        Case ".JPG" : fmt = Imaging.ImageFormat.Jpeg
                                        Case ".BMP" : fmt = Imaging.ImageFormat.Bmp
                                        Case ".GIF" : fmt = Imaging.ImageFormat.Gif
                                        Case ".PNG" : fmt = Imaging.ImageFormat.Png
                                        Case ".TIF" : fmt = Imaging.ImageFormat.Tiff
                                    End Select
                                    filename = .FileName
                                    PageImage.Save(filename, fmt)
                                    SaveSetting(REGAPP, "SendToImage", "Directory", IO.Path.GetDirectoryName(filename))
                                Else
                                    Exit Sub
                                End If
                                .Dispose()
                            End With
                        End If
                    End If

                Else 'just send current (or all) graphs to clipboard or files, one at a time

                    With ActiveGraphTab(CurrentTab).Zed
                        If ImageFormat = frmImage.enumFormat.Metafile Then
                            ClipboardMetafileHelper.CopyToClip(.GraphPane)
                        ElseIf ImageFormat = frmImage.enumFormat.Bitmap Then
                            .Copy(False)
                        Else
                            .Visible = False
                            filename = GetSetting(REGAPP, "SendToImage", "Directory", AppDataPath) & "\" & GraphForm.TabGraph.TabPages(CurrentTab).Text & ".jpg"
                            If ExpertMode And CurrentTab <> MinTab Then
                                .SaveIn(filename)
                            Else
                                filename = .SaveAs(filename)
                                If filename <> "" Then SaveSetting(REGAPP, "SendToImage", "Directory", IO.Path.GetDirectoryName(filename))
                            End If
                            .Visible = True
                        End If
                    End With
                    CurrentTab += 1

                End If

                'If filename = "" Then Exit While

                If ImageFormat = frmImage.enumFormat.File Then
                    If filename <> "" And Not AlreadyWarned And Not ExpertMode Then
                        WarningMsg("The graph image has been send to the graphics file; " &
                                   IIf(Resize, "if used so that it prints {0} inches wide and {1} inches high, fonts and symbols will be scaled properly.",
                                               "it is an exact replica of the image that appears on your screen.") &
                                   "\n\nThis message will not reappear this session.", ImageWidth, ImageHeight)
                    End If
                ElseIf CurrentTab - 1 < MaxTab Then
                    WarningMsg("The graph image has been send to the clipboard; " &
                               IIf(Resize, "if used so that it prints {0} inches wide and {1} inches high, fonts and symbols will be scaled properly.",
                                           "it is an exact replica of the image that appears on your screen.") &
                               IIf(CurrentTab - 1 < MaxTab, "\n\nEach tab is being placed on the clipboard sequentially, replacing the prior clipboard contents. The graph has just been copied there.\n\n" &
                                                        "Switch to your other application and paste this image at the desired location (hint: use Alt-Tab to switch applications, and Cntl-V to paste). " &
                                                        "Then return here and click OK or press the Enter key to proceed to the next graph tab.",
                                                        "\n\nThe graph image has just been copied to the clipboard. " &
                                                        "Switch to your other application and paste this image at the desired location (hint: use Alt-Tab to switch applications, and Cntl-V to paste)."),
                               ImageWidth, ImageHeight)
                End If
                AlreadyWarned = True

            End While

        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Put image of specified graph tab into correct position on graphics image
    ''' </summary>
    ''' <param name="GraphTab">Graph to render</param>
    ''' <param name="BaseDimension">Width (inches) to use to set font size (usually full width of page)</param>
    ''' <param name="PrintWidth">Width (inches) of cell where graph is to be placed</param>
    ''' <param name="PrintHeight">Height (inches) of cell where graph is to be placed</param>
    ''' <param name="XOffset">Horizontal offset (inches) of upper left of graph</param>
    ''' <param name="YOffset">Vertical offset (inches) of upper left of graph</param>
    ''' <param name="Resolution">Desired resolution (dpi) in destination image</param>
    ''' <param name="g">Object to render to </param>
    Private Sub RenderGraphPane(GraphTab As clsGraphTab, BaseDimension As Double, PrintWidth As Double, PrintHeight As Double, XOffset As Double, YOffset As Double, Resolution As Integer, g As Graphics)

        With GraphTab
            Dim dpiX As Integer = .Zed.CreateGraphics.DpiX

            .Zed.Visible = False

            'resize graph to provide desired resolution

            .Zed.GraphPane.IsFontsScaled = True
            .Zed.GraphPane.IsPenWidthScaled = True
            Dim SavedDrawBorders As Boolean = .Zed.GraphPane.Border.IsVisible
            .Zed.GraphPane.Border.IsVisible = Layouts(ActiveLayoutName).DrawBorders
            .Zed.Dock = DockStyle.None

            Dim SavedFontScaleFactor As Double = .GraphOptions.FontScaleFactor
            .GraphOptions.FontScaleFactor = 1.0

            .Zed.GraphPane.BaseDimension = BaseDimension
            .Zed.Width = PrintWidth * Resolution
            .Zed.Height = PrintHeight * Resolution
            .Zed.Refresh()

            Dim img As Image = .Zed.GraphPane.GetImage(.Zed.Width, .Zed.Height, Resolution)
            g.DrawImage(img, New Point(XOffset * Resolution, YOffset * Resolution))

            .GraphOptions.FontScaleFactor = SavedFontScaleFactor
            .Zed.Dock = DockStyle.Fill
            .Zed.GraphPane.IsFontsScaled = False
            .Zed.GraphPane.IsPenWidthScaled = False
            .Zed.Visible = True
            .Zed.GraphPane.Border.IsVisible = SavedDrawBorders

        End With
    End Sub

    ''' <summary>
    ''' Put image of specified graph tab into correct position on graphics image
    ''' </summary>
    ''' <param name="Html">HTML text to render</param>
    ''' <param name="BaseDimension">Width (inches) to use to set font size (usually full width of page)</param>
    ''' <param name="PrintWidth">Width (inches) of cell where graph is to be placed</param>
    ''' <param name="PrintHeight">Height (inches) of cell where graph is to be placed</param>
    ''' <param name="XOffset">Horizontal offset (inches) of upper left of graph</param>
    ''' <param name="YOffset">Vertical offset (inches) of upper left of graph</param>
    ''' <param name="Resolution">Desired resolution (dpi) in destination image</param>
    ''' <param name="g">Object to render to </param>
    Private Sub RenderGraphPane(Html As String, BaseDimension As Double, PrintWidth As Double, PrintHeight As Double, XOffset As Double, YOffset As Double, Resolution As Integer, g As Graphics)

        Dim dpiX As Integer = Me.CreateGraphics.DpiX

        Dim wb As New WebBrowser
        With wb
            'don't want to render to screen resolution: when it prints it looks fuzzy
            'must increase font size when increase client size; do this by trial and error
            Dim SizeMult As Double = 3 * 600 / Resolution

            .ClientSize = New Size(PrintWidth * dpiX * SizeMult, PrintHeight * dpiX * SizeMult)
            .ScrollBarsEnabled = False
            .DocumentText = Html
            While .ReadyState <> WebBrowserReadyState.Complete
                Application.DoEvents()
            End While
            Dim bmp As New Bitmap(.ClientSize.Width, .ClientSize.Height)
            bmp.SetResolution(dpiX * SizeMult, dpiX * SizeMult)

            .DrawToBitmap(bmp, New Rectangle(0, 0, .ClientSize.Width, .ClientSize.Height))

            g.DrawImage(bmp, New Point(XOffset * Resolution, YOffset * Resolution))

            .Dispose()
            bmp.Dispose()
        End With
    End Sub

    Private Sub mnuDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuDrawArrow.Click, mnuDrawLine.Click, mnuDrawBox.Click, mnuDrawEllipse.Click, mnuDrawTextbox.Click
        With ActiveGraphTab()
            .DrawMode = clsGraphTab.enumDrawMode.FirstPoint
            .Zed.Cursor = Cursors.SizeAll
            .Zed.IsEnableZoom = False
            If sender Is mnuDrawArrow Then
                .DrawType = clsGraphTab.enumDrawType.Arrow
            ElseIf sender Is mnuDrawLine Then
                .DrawType = clsGraphTab.enumDrawType.Line
            ElseIf sender Is mnuDrawBox Then
                .DrawType = clsGraphTab.enumDrawType.Box
            ElseIf sender Is mnuDrawEllipse Then
                .DrawType = clsGraphTab.enumDrawType.Ellipse
            ElseIf sender Is mnuDrawTextbox Then
                .DrawType = clsGraphTab.enumDrawType.Textbox
            End If
        End With
    End Sub

    Private Sub mnuDrawColor_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuDrawColor.Click
        With New ColorDialog
            .Color = ActiveGraphTab.DrawColor
            If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                ActiveGraphTab.DrawColor = .Color
                .Dispose()
            End If
        End With
    End Sub

    Private Sub mnuDraw2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuDrawDeleteAll.Click, mnuDrawHideAll.Click, mnuDrawShowAll.Click
        With ActiveGraphTab.Zed.GraphPane
            If sender Is mnuDrawDeleteAll Then
                For i As Integer = .GraphObjList.Count - 1 To 0 Step -1
                    If .GraphObjList(i).Tag Is Nothing Then .GraphObjList.RemoveAt(i)
                Next
            Else
                For Each GraphObj As ZedGraph.GraphObj In .GraphObjList
                    GraphObj.IsVisible = (sender Is mnuDrawShowAll)
                Next
            End If
        End With
        ActiveGraphTab.Zed.Refresh()
    End Sub

    Private Sub tbDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tbDrawArrow.Click, tbDrawLine.Click, tbDrawBox.Click, tbDrawEllipse.Click, tbDrawEllipse.Click, tbDrawTextbox.Click, tbDrawDeleteAll.Click, tbDrawShowAll.Click, tbDrawHideAll.Click
        If sender Is tbDrawArrow Then
            mnuDrawArrow.PerformClick()
        ElseIf sender Is tbDrawLine Then
            mnuDrawLine.PerformClick()
        ElseIf sender Is tbDrawBox Then
            mnuDrawBox.PerformClick()
        ElseIf sender Is tbDrawEllipse Then
            mnuDrawEllipse.PerformClick()
        ElseIf sender Is tbDrawTextbox Then
            mnuDrawTextbox.PerformClick()
        ElseIf sender Is tbDrawDeleteAll Then
            mnuDrawDeleteAll.PerformClick()
        ElseIf sender Is tbDrawShowAll Then
            mnuDrawShowAll.PerformClick()
        ElseIf sender Is tbDrawHideAll Then
            mnuDrawHideAll.PerformClick()
        End If
    End Sub

    Private Sub trkAnim_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles trkAnim.VisibleChanged
        If trkAnim.Visible Then ResetAnimationLimits()
    End Sub

    '''' <summary>
    '''' Restore backed up text files to tables in current project
    '''' </summary>
    'Friend Sub FileMgmtProjectRestore()
    '    If Not TestConnection() Then Exit Sub
    '    Try
    '        'for right now, just import all non-system tables
    '        'todo: use new project table to export only tables associated with this project
    '        'todo: store default zipfile archive for project in project table
    '        Dim ZipFile As String
    '        With New OpenFileDialog
    '            .AddExtension = True
    '            .CheckFileExists = True
    '            .DefaultExt = ".zip"
    '            .InitialDirectory = AppDataPath
    '            .FileName = Project.Name & ".zip"
    '            .Filter = "Archive file (*.zip)|*.zip"
    '            .Title = "Select Archive"
    '            If .ShowDialog = DialogResult.Cancel Then Exit Sub
    '            ZipFile = .FileName
    '        End With
    '        EnableMenus(False)
    '        With Project
    '            If Not My.Computer.FileSystem.DirectoryExists(TempPath) Then My.Computer.FileSystem.CreateDirectory(TempPath)
    '            Dim fze As New ICSharpCode.SharpZipLib.Zip.FastZipEvents
    '            fze.Progress = New ICSharpCode.SharpZipLib.Core.ProgressHandler(AddressOf ZipProgress)
    '            Dim zip As New ICSharpCode.SharpZipLib.Zip.FastZip(fze)
    '            WriteProgress("Extracting from archive file " & ZipFile, ProgressBarStyle.Marquee)
    '            zip.ExtractZip(ZipFile, TempPath, "")
    '            ProgressComplete()
    '            For Each FileName As String In My.Computer.FileSystem.GetFiles(TempPath, FileIO.SearchOption.SearchTopLevelOnly)
    '                Dim TableName As String = Project.DB.GetValidTableName(IO.Path.GetFileNameWithoutExtension(FileName))
    '                If TableName = "" Then Exit For
    '                If Not .ImportTable(TableName, FileName) Then Exit Sub
    '            Next
    '            My.Computer.FileSystem.DeleteDirectory(TempPath, FileIO.DeleteDirectoryOption.DeleteAllContents)
    '        End With
    '        Project.SynchTrackingRecords(True)
    '    Catch ex As DbSqlException
    '        WarningMsg(ex.Message)
    '    Catch ex As Exception
    '        ErrorMsg("Sorry, but an unhandled error has occurred.", ex)
    '    Finally
    '        EnableMenus(True)
    '    End Try
    'End Sub

    ''' <summary>
    ''' For each table assigned to the current set of graphs, add to archive
    ''' </summary>
    Private Sub mnuFileArchive_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFileArchive.Click
        Try
            If GroupFileName = "" Then
                WarningMsg("You cannot archive a graph until you have saved the graph file.")
                Exit Sub
            End If
            Dim ZipFile As String
            With New SaveFileDialog
                .AddExtension = True
                .CreatePrompt = False
                .DefaultExt = ".zip"
                .InitialDirectory = AppDataPath
                .FileName = IO.Path.ChangeExtension(GroupFileName, ".zip")
                .Filter = "Archive Files (*.zip)|*.zip"
                .OverwritePrompt = True
                .Title = "Select Archive"
                If .ShowDialog(Me) = DialogResult.Cancel Then Exit Sub
                ZipFile = .FileName
            End With

            If My.Computer.FileSystem.FileExists(ZipFile) Then My.Computer.FileSystem.DeleteFile(ZipFile)

            Dim zf As ICSharpCode.SharpZipLib.Zip.ZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile.Create(ZipFile)

            Dim WRDBTblFound As Boolean = False
            Me.Enabled = False

            For Each tbl As clsTable In OpenTables
                Dim tblfile As String = ""
                Select Case tbl.TableType
                    Case clsTable.enumTableType.BMD
                        tblfile = tbl.DataSource
                    Case clsTable.enumTableType.WRDBData
                        tblfile = IO.Path.GetDirectoryName(tbl.DataSource)
                    Case clsTable.enumTableType.Folder
                        tblfile = tbl.DataSource & tbl.TableFile
                    Case clsTable.enumTableType.Database
                        tblfile = tbl.DataSource
                    Case clsTable.enumTableType.WRDB4, clsTable.enumTableType.WRDB5
                        WRDBTblFound = True
                End Select
                If tblfile <> "" Then
                    If tbl.TableType = clsTable.enumTableType.WRDBData Then
                        For Each s As String In My.Computer.FileSystem.GetFiles(tblfile, FileIO.SearchOption.SearchTopLevelOnly, "*" & IO.Path.GetExtension(tbl.DataSource))
                            WriteProgress(Me, "Updating archive file with {0}...", s)
                            zf.BeginUpdate()
                            zf.Add(s)
                            zf.CommitUpdate()
                        Next
                    Else
                        WriteProgress(Me, "Updating archive file with {0}...", tbl.ToString)
                        If tbl.WRDBProject IsNot Nothing Then tbl.WRDBProject.DB.Connection.Close()
                        zf.BeginUpdate()
                        zf.Add(tblfile)
                        zf.CommitUpdate()
                    End If
                End If
            Next

            zf.BeginUpdate()
            zf.Add(GroupFileName)
            zf.CommitUpdate()

            zf.Close()
            frmInfoMsg.ShowInfoMsg("Send to Archive", "Archive file {0} has been created containing the .Graph file and all the data files referenced by it." & IIf(WRDBTblFound, " Note that one or more referenced tables were contained in client/server databases for which the data could not be archived.", ""), ZipFile)

        Catch ex As Exception
            ErrorMsg("Unable to create archive file.", ex)
        Finally
            WriteProgress(Me)
            Me.Enabled = True
        End Try
    End Sub

    Private Sub mnuViewZoomMode_DropDownItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuViewZoomMode.DropDownItemClicked
        ActiveGraphTab.GraphOptions.ZoomOption = mnuViewZoomMode.DropDownItems.IndexOf(e.ClickedItem) + 1
    End Sub

    Private Sub mnuViewZoomMode_DropDownOpening(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuViewZoomMode.DropDownOpening
        For Each mnu As ToolStripMenuItem In mnuViewZoomMode.DropDownItems
            mnu.Checked = False
        Next
        With ActiveGraphTab.GraphOptions
            Select Case .ZoomOption
                Case enumZoomOptions.Horizontal : mnuZoomH.Checked = True
                Case enumZoomOptions.Vertical : mnuZoomV.Checked = True
                Case enumZoomOptions.Both : mnuZoomB.Checked = True
                Case enumZoomOptions.Auto : mnuZoomA.Checked = True
            End Select
        End With
    End Sub

    Private Sub mnu_DropDownOpening(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuFile.DropDownOpening, mnuView.DropDownOpening, mnuDraw.DropDownOpening, mnuGraph.DropDownOpening, mnuTools.DropDownOpening, mnuHelp.DropDownOpening
        EnableMenus()
        tbAnimPause.PerformClick()
    End Sub

    Private Sub mnuTabGraph_Opening(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles mnuTabGraph.Opening
        tbAnimPause.PerformClick()
    End Sub

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub

    Private Sub lstSeries_ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles lstSeries.ItemCheck
        Try
            If lstSeries.SelectedIndex <> -1 Then
                With ActiveGraphTab.Series(lstSeries.SelectedIndex)
                    .Visible = e.NewValue
                End With
                With ActiveGraphTab.Zed
                    .AxisChange()
                    .Refresh()
                End With
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub lstSeries_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lstSeries.SelectedIndexChanged
        pgSeries.SelectedObject = ActiveGraphTab.Series(lstSeries.SelectedIndex)
        pgGraphOptions.SelectedObject = ActiveGraphTab.GraphOptions
    End Sub

    Private Sub pg_PropertyValueChanged(ByVal s As Object, ByVal e As System.Windows.Forms.PropertyValueChangedEventArgs) Handles pgSeries.PropertyValueChanged, pgGraphOptions.PropertyValueChanged, pgAxes.PropertyValueChanged
        Try
            With ActiveGraphTab.Zed
                .AxisChange()
                .Refresh()
            End With
            CType(s, PropertyGrid).Refresh()
            _IsModified = True
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' This is required because exception occurs when collapsible splitpanel starts out with zero width
    ''' </summary>
    Private Sub tabProperties_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles tabProperties.Resize
        If tabProperties.Width = 0 Then tabProperties.Width = 10
    End Sub

    Private Sub Statusbar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Statusbar.Click
        _IsLoadCancelled = True
        _IsBuildCancelled = True
    End Sub

    Private Function GetTable(Optional CalibrationOnly As Boolean = False) As clsTable
        If OpenTables.Count = 0 Then
            With New frmSelectTable("", ExpertMode)
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    For Each tbl As clsTable In .SelectedTables
                        OpenTables.Add(tbl)
                    Next
                Else
                    Return Nothing
                End If
            End With
        End If

        If OpenTables.Count = 1 Then
            Return OpenTables(0)
        Else
            With New frmClose
                .Text = "Select Table"
                .btnSelectAll.Enabled = False
                .lstTables.SelectionMode = SelectionMode.One
                Dim lsttbl As clsTable = Nothing
                For Each tbl As clsTable In OpenTables
                    If Not CalibrationOnly OrElse tbl.TableType = clsTable.enumTableType.Calibration Then
                        .lstTables.Items.Add(tbl.ToString)
                        lsttbl = tbl
                    End If
                Next
                If .lstTables.Items.Count = 1 Then
                    Return lsttbl
                ElseIf .lstTables.Items.Count = 0 Then
                    WarningMsg("No calibration datasets have been defined yet. Using menu items on the ""Files | Data Files and Tables"" menu please follow this procedure:\n\n" &
                               "\t\b Open existing data tables or files (usually a WRDB table for measured data and BMD file for simulated)\n\n" &
                               "\t\b Select Manage Calibration Datasets menu to create a new dataset and then proceed to map stations and parameters from each existing table\n\n" &
                               "\t\b Return to this menu to build tabs and layouts\n\nSee the Help manual for more information.")
                    Return Nothing
                Else
                    If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                        For Each tbl As clsTable In OpenTables
                            If Not CalibrationOnly OrElse tbl.TableType = clsTable.enumTableType.Calibration Then
                                If tbl.ToString = .lstTables.Text Then Return tbl
                            End If
                        Next
                        Return Nothing
                    Else
                        Return Nothing
                    End If
                End If
            End With
        End If
    End Function

    Private Sub mnuToolsBuild_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuToolsBuildSingle.Click, mnuToolsBuildMultiP.Click, mnuToolsBuildMultiSP.Click, mnuToolsBuildCalib.Click
        Try
            Dim SelectedTable As clsTable = GetTable(sender Is mnuToolsBuildCalib)
            If SelectedTable Is Nothing Then Exit Sub

            WriteProgress(GraphForm, "Getting lists of stations and pcodes...")

            Dim staList As Generic.List(Of String) = SelectedTable.GetStationList("") : If staList Is Nothing Then Exit Sub
            Dim pcdList As Generic.List(Of String) = SelectedTable.GetPCodeList("")
            Dim chkTitles, chkStats, chkPCodeLimits As Boolean
            Dim txtTitle As String

            With New frmSelectStaPCode
                With .chkStation
                    .Items.AddRange(staList.ToArray)
                    For i As Integer = 0 To .Items.Count - 1
                        .SetItemChecked(i, True)
                    Next
                End With
                With .chkParameter
                    .Items.AddRange(pcdList.ToArray)
                    For i As Integer = 0 To .Items.Count - 1
                        .SetItemChecked(i, True)
                    Next
                End With
                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                    staList.Clear()
                    For Each s As String In .chkStation.CheckedItems
                        staList.Add(s)
                    Next
                    pcdList.Clear()
                    For Each s As String In .chkParameter.CheckedItems
                        pcdList.Add(s)
                    Next
                    chkTitles = .chkTitle.Checked
                    chkStats = .chkStats.Checked
                    chkPCodeLimits = .chkPCodeLimits.Checked
                    txtTitle = .txtTitle.Text
                    SaveSetting(REGAPP, Name, "TitlePrefix", txtTitle)
                    .Dispose()
                Else
                    .Dispose()
                    Exit Sub
                End If
            End With

            Dim numSeries As Integer = 0
            For Each pcd As String In pcdList
                For Each sta As String In SelectedTable.GetStationListByPCode(pcd)
                    If staList.Contains(sta) Then numSeries += 1
                Next
            Next

            If sender Is mnuToolsBuildCalib Then numSeries *= 3 'will add timeseries, scatter, and probability

            WriteProgress(GraphForm)

            If Not ExpertMode AndAlso WarningMsg("You are about to add {0} series to one or more tabs; do you want to continue?", numSeries) = Windows.Forms.DialogResult.Cancel Then Exit Sub

            If sender Is mnuToolsBuildSingle Then AddGraphTab()

            Dim seriesNum As Integer = 0

            _IsBuildCancelled = False

            TabGraph.Visible = False

            Dim Layout As clsLayout = Nothing

            If sender Is mnuToolsBuildCalib Then
                If Not Layouts.TryGetValue("Calibration", Layout) Then
                    Layouts.Add("Calibration", New clsLayout("Calibration"))
                End If
                Layout = Layouts("Calibration")
                With Layout
                    .PageContents.Clear()
                    .NumCols = 2
                    .NumRows = 2
                    .Landscape = False
                    .DrawBorders = True
                    .AutoAssign = False
                End With
            End If

            For Each pcd As String In pcdList
                If sender Is mnuToolsBuildMultiP Or sender Is mnuToolsBuildCalib Then AddGraphTab()
                For Each sta As String In SelectedTable.GetStationListByPCode(pcd)
                    If staList.Contains(sta) Then
                        Dim ThisPcd As String = StringSplit(pcd, " - ")(0)
                        Dim ThisSta As String = StringSplit(sta, " - ")(0)

                        If sender Is mnuToolsBuildCalib Then 'make sure there are data for both measured and simulated
                            If SelectedTable.Calibration.GetData(ThisSta, ThisPcd, clsCalibration.enumDataType.Measured).Rows.Count = 0 OrElse
                               SelectedTable.Calibration.GetData(ThisSta, ThisPcd, clsCalibration.enumDataType.Simulated).Rows.Count = 0 Then
                                Continue For
                            End If
                        End If

                        Dim PaneContents As New clsPaneContents

                        If sender Is mnuToolsBuildMultiSP Or sender Is mnuToolsBuildCalib Then AddGraphTab()
                        With ActiveGraphTab()
                            .AddSeries(SelectedTable, ThisSta, ThisPcd, Date.MinValue, enumTimeWindow.All, ThisSta, ThisPcd, "", clsSeries.enumYAxis.Left, 0, True)
                            If sender Is mnuToolsBuildMultiP Then
                                .Name = ThisPcd
                                .GraphOptions.GraphTitle = .Name
                            ElseIf sender Is mnuToolsBuildMultiSP Or sender Is mnuToolsBuildCalib Then
                                .Name = ThisPcd & " at " & ThisSta
                                .GraphOptions.GraphTitle = .Name
                            End If
                            .ZoomExtents()
                            If sender Is mnuToolsBuildCalib Then
                                PaneContents.Item(0, 0) = ActiveGraphTab.Name
                            End If
                        End With
                        seriesNum += 1
                        WriteProgress(GraphForm, seriesNum, numSeries, "Adding series for {0} at {1} (click status bar to cancel)...", pcd, sta)

                        If sender Is mnuToolsBuildCalib Then 'have already added time series graph; add other graph types

                            'make time window match the time aggregation period
                            Dim TimeWindow As enumTimeWindow = enumTimeWindow.All
                            Select Case SelectedTable.Calibration.TimeAggregation
                                Case clsCalibration.enumTimeAgg.None : TimeWindow = enumTimeWindow.All 'just pick closest value & don't use time window
                                Case clsCalibration.enumTimeAgg.Hour : TimeWindow = enumTimeWindow._1_Hour
                                Case clsCalibration.enumTimeAgg.Day : TimeWindow = enumTimeWindow._1_Day
                                Case clsCalibration.enumTimeAgg.Week : TimeWindow = enumTimeWindow._1_Week
                                Case clsCalibration.enumTimeAgg.Month : TimeWindow = enumTimeWindow._1_Month
                            End Select

                            With Layout
                                'add probability graph
                                AddGraphTab()
                                seriesNum += 1
                                WriteProgress(GraphForm, seriesNum, numSeries, "Adding probability series for {0} at {1} (click status bar to cancel)...", pcd, sta)
                                With ActiveGraphTab()
                                    .Name = String.Format("Prob {0} at {1}", ThisPcd, ThisSta)
                                    .GraphType = enumGraphType.Probability
                                    .AddSeries(SelectedTable, ThisSta, ThisPcd, Date.MinValue, TimeWindow, ThisSta, ThisPcd, "", clsSeries.enumYAxis.Left, 0, True)
                                    .Reset()
                                    .SetGraphTitle()
                                    .Zed.AxisChange()
                                    .Zed.Refresh()
                                    If .Series.Count = 1 Then ActiveGraphTab.ZoomExtents()
                                    PaneContents.Item(1, 0) = .Name
                                End With

                                'add scatter graph
                                AddGraphTab()
                                seriesNum += 1
                                WriteProgress(GraphForm, seriesNum, numSeries, "Adding scatter series for {0} at {1} (click status bar to cancel)...", pcd, sta)
                                With ActiveGraphTab()
                                    .Name = String.Format("Scatter {0} at {1}", ThisPcd, ThisSta)
                                    .GraphType = enumGraphType.Scatter
                                    .AnimationInfo.TimeWindow = TimeWindow
                                    .AddSeries(SelectedTable, ThisSta, ThisPcd, Date.MinValue, TimeWindow, ThisSta, ThisPcd, "", clsSeries.enumYAxis.Left, 0, True)

                                    If .Series.Count > 0 Then
                                        'add best fit line
                                        Dim ser As clsSeries = .Series(0)
                                        Dim zc As New ZedGraph.LineItem(ser.Label, New ZedGraph.PointPairList, Color.Fuchsia, SymbolType.None, 1)
                                        Dim FitStats As String = ""
                                        zc.IsVisible = ser.ZedCurve.IsVisible
                                        zc.IsX2Axis = ser.ZedCurve.IsX2Axis
                                        zc.IsY2Axis = ser.ZedCurve.IsY2Axis
                                        zc.YAxisIndex = ser.ZedCurve.YAxisIndex
                                        frmSeries.ComputeScatterFit(enumCurveFit.Linear, ser.ZedCurve, zc, FitStats)
                                        zc.Label.Text &= " - Linear Fit"
                                        .AddSeries(ser, zc, FitStats)
                                    End If
                                    .Reset()
                                    .SetGraphTitle()
                                    .Zed.AxisChange()
                                    .Zed.Refresh()
                                    If .Series.Count = 1 Then ActiveGraphTab.ZoomExtents()
                                    PaneContents.Item(1, 1) = .Name
                                End With

                                'add calibration report
                                PaneContents.Item(0, 1) = clsCalibration.GetCalibrationString(SelectedTable.Calibration.Name, "Default", ThisSta, ThisPcd)

                                .PageContents.Add(PaneContents)
                            End With
                        End If

                        If _IsBuildCancelled Then Exit For
                    End If
                Next
                If _IsBuildCancelled Then Exit For
            Next

            'annotate graphs if requested
            WriteProgress(GraphForm, "Annotating graphs...")
            If chkTitles Then AnnotateTitles(txtTitle)
            If chkStats Then mnuToolsAnnotateStats.PerformClick()
            If chkPCodeLimits Then mnuToolsAnnotateLimits.PerformClick()

        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            WriteProgress(GraphForm)
            EnableMenus()
            _IsModified = True
            TabGraph.Visible = True
        End Try
    End Sub

    Private Sub mnuViewProperties_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuViewProperties.Click
        splitMain.ToggleState()
    End Sub

    Private Sub splitMain_SplitterMoved(ByVal sender As Object, ByVal e As System.Windows.Forms.SplitterEventArgs) Handles splitMain.SplitterMoved
        mnuViewProperties.Checked = Not splitMain.IsCollapsed
    End Sub

    Private _Axis As clsAxis

    Private Sub cboAxis_SelectionChangeCommitted(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboAxis.SelectionChangeCommitted
        Try
            With cboAxisIndex
                .Items.Clear()
                Select Case cboAxis.SelectedIndex
                    Case 0 : .Items.Add("1") : clsGraphTab.CurrentAxisType = enumAxisType.XAxis 'set to ConvAxisType will offer up appropriate axis types
                    Case 1, 2 : .Items.AddRange(New String() {"1", "2", "3", "4", "5"}) : clsGraphTab.CurrentAxisType = enumAxisType.YAxis
                End Select
                .SelectedIndex = 0
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub cboAxisIndex_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboAxisIndex.SelectedIndexChanged
        SetAxisProperties()
    End Sub

    Friend Sub SetAxisProperties()
        Try
            Dim AxisType As clsAxis.enumAxis
            Select Case cboAxis.SelectedIndex
                Case 0
                    AxisType = clsAxis.enumAxis.XAxis
                    clsGraphTab.CurrentAxisType = enumAxisType.XAxis 'set to ConvAxisType will offer up appropriate axis types
                Case 1
                    AxisType = clsAxis.enumAxis.YAxis
                    clsGraphTab.CurrentAxisType = enumAxisType.YAxis 'set to ConvAxisType will offer up appropriate axis types
                Case 2
                    AxisType = clsAxis.enumAxis.Y2Axis
                    clsGraphTab.CurrentAxisType = enumAxisType.YAxis 'set to ConvAxisType will offer up appropriate axis types
            End Select
            _Axis = New clsAxis(ActiveGraphTab.Zed, AxisType, cboAxisIndex.SelectedIndex, ActiveGraphTab.GraphOptions.FontScaleFactor)
            pgAxes.SelectedObject = _Axis
            ActiveGraphTab.Zed.AxisChange()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub btnManage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnManage.Click
        mnuToolsManage.PerformClick()
    End Sub

    Private Sub btnRemove_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRemove.Click
        Try
            With ActiveGraphTab()
                'get list of unique rows that are currently selected
                Dim ser As clsSeries = .Series(lstSeries.SelectedIndex)
                ser.RemoveZedCurve()
                .Series.Remove(ser)
                .SetGraphTitle()
                .ResetYAxes()
                .Zed.AxisChange()
                .Zed.Refresh()
            End With
            FillSeriesList()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuCustomize_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuCustomize.Click
        With New frmToolbar(tbMain)
            .ShowDialog(Me)
            .Dispose()
        End With
        EnableGraphMenus()
    End Sub

    Private Sub AnnotateTitles(TitlePrefix As String)
        If TitlePrefix.Split("~").Length <> 2 Then
            WarningMsg("The title template must contain exactly one tilde placeholder (~) where the Branch ID will be inserted.")
            Exit Sub
        End If
        SaveSetting(REGAPP, Name, "TitlePrefix", TitlePrefix)

        'for each tab find the first referenced Branch_ID in a series
        For i As Integer = 0 To TabGraph.TabCount - 2
            With ActiveGraphTab(i)
                Dim BranchID As String = ""
                For Each ser As clsSeries In .Series
                    With ser
                        If .Table IsNot Nothing Then
                            Select Case .Table.TableType
                                Case clsTable.enumTableType.WRDB4, clsTable.enumTableType.WRDB5
                                    With .Table.WRDBProject
                                        Dim lst As Generic.List(Of String) = .DB.GetRecordList("Stations", "Branch_ID", String.Format("WHERE Station_ID='{0}'", ser.StationID))
                                        If lst.Count = 1 Then
                                            If Not String.IsNullOrEmpty(lst(0)) Then
                                                BranchID = lst(0)
                                                Exit For
                                            End If
                                        End If
                                    End With
                            End Select
                        End If
                    End With
                Next
                If BranchID <> "" Then .GraphOptions.GraphTitle = TitlePrefix.Replace("~", BranchID)
            End With
        Next
    End Sub

    Private Sub mnuToolsAnnotate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuToolsAnnotateTitles.Click, mnuToolsAnnotateStats.Click, mnuToolsAnnotateLimits.Click
        Try
            If sender Is mnuToolsAnnotateTitles Then
                Dim TitlePrefix As String = GetSetting(REGAPP, Name, "TitlePrefix", "Branch ID: ~")
                TitlePrefix = InputBox("This routine will reset the graph title for each tab using the first referenced Branch ID in any series in the graph. That Branch ID will be inserted at the location of a tilde (~) placeholder in a template that you specify:", "Annotate Titles", TitlePrefix)
                If TitlePrefix = "" Then Exit Sub
                AnnotateTitles(TitlePrefix)
            ElseIf sender Is mnuToolsAnnotateStats Then
                'open statsform, then cycle through each tab; stats form gets refreshed automatically
                If StatsForm Is Nothing Then StatsForm = New frmStats
                StatsForm.Show()
                For i As Integer = 0 To TabGraph.TabCount - 2
                    TabGraph.SelectedIndex = i
                    'must delay to give the form time to update and refresh the statistics
                    Threading.Thread.Sleep(500)
                    'treeview in form has been refreshed; if a single node, use it; otherwise use last one (summary of all series)
                    StatsForm.Focus()
                    With StatsForm.tvStats
                        If .Nodes.Count = 0 Then
                            'no series
                            Continue For
                        ElseIf .Nodes.Count = 1 Then
                            .SelectedNode = .Nodes(0)
                        Else
                            .SelectedNode = .Nodes(0)
                            For Each n As TreeNode In .Nodes
                                If n.Text = "Summary for All Series" Then
                                    .SelectedNode = n
                                    Exit For
                                End If
                            Next
                        End If
                        .Focus()
                        StatsForm.mnuNotes.PerformClick()
                    End With
                Next
                StatsForm.Close()
            ElseIf sender Is mnuToolsAnnotateLimits Then
                frmInfoMsg.ShowInfoMsg("Annotate PCode Limits", "This tool will add calculated PCode limit series to each graph tab. Note that only the first series on each graph will be examined, so if you have graphs with multiple PCodes or which may have Criteria Overrides for one or more series, you will need to manually add additional limit lines.")
                For i As Integer = 0 To TabGraph.TabCount - 2
                    With ActiveGraphTab(i)
                        Dim ser As clsSeries = .Series(0)
                        Dim zc As New ZedGraph.LineItem(ser.Label, New ZedGraph.PointPairList, Color.Fuchsia, SymbolType.None, 1)
                        Dim FitStats As String = ""
                        zc.IsVisible = ser.ZedCurve.IsVisible
                        zc.IsX2Axis = ser.ZedCurve.IsX2Axis
                        zc.IsY2Axis = ser.ZedCurve.IsY2Axis
                        zc.YAxisIndex = ser.ZedCurve.YAxisIndex
                        Dim Criteria As New WRDB.Project.clsCriteria(ser.Table.WRDBProject, ser.Table.TableName)
                        frmSeries.ComputeLimits(Criteria, ser.StationID, ser.PCode, ser.DateTime, ser.ZedCurve, zc, FitStats)
                        .AddSeries(ser, zc, FitStats)
                        .Zed.AxisChange()
                        .Zed.Refresh()
                        Criteria.Dispose()
                    End With
                Next
            End If
            ActiveGraphTab.Zed.Refresh()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuFileCalibration_Click(sender As System.Object, e As System.EventArgs) Handles mnuFileCalibration.Click
        With New frmCalibrationMgr
            .ShowDialog(Me)
            .Dispose()
            mnuViewRefresh.PerformClick()
            _IsModified = True
        End With
    End Sub

    Private Sub mnuFileOpenExternal_Click(sender As Object, e As System.EventArgs) Handles mnuFileOpenExternal.Click
        'this points to WRDB INI file which contains all project information (and database connections used by)
        Dim IniFile As New clsWRDBIniFile()

        Try
            frmInfoMsg.ShowInfoMsg("Open External Database", "This tool is used to manage connections to non-WRDB databases for the purpose of graphing the data. To create this connection, you must know the database type, location, name, and username and password. This is only available for client-server databases like SQL Server, Oracle, Firebird, and MySQL.\n\nAfter configuring the connection to the database, you can create a new or edit an existing table mapping using the Field Mapping Form to map fields in the external database table to standard WRDB fields.\n\nNote that data from the external database are imported to a temporary table for graphing and the source data will not be altered in any way.")
            With New External.clsExternalData(IniFile, Nothing)
                .ShowManageConnections(Me)

                'If .ShowSelectTable(Me, False) Then
                '    Dim tbl As New clsTable
                '    If tbl.CreateExternalTable(.ConnectionName, .TableConnectionName) Then
                '        OpenTables.Add(tbl)
                '        mnuToolsManage.PerformClick()
                '    End If
                'End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            IniFile.Save()
        End Try
    End Sub

    Private Sub mnuToolsGIS_Click(sender As Object, e As System.EventArgs) Handles mnuToolsGIS.Click
        With New WRDB.GIS.frmGIS(, True)
            .Show(Me)
        End With
    End Sub

End Class
